Refactor the structure of FS subsystem

1. Move the system call handling functions into the "syscalls.rs"
2. Split syscall memory safe implementations into small sub-modules
3. Move the unix_socket and io_multiplexing into "net"
4. Remove some unnecessary code
This commit is contained in:
LI Qing 2020-01-21 07:27:59 +00:00 committed by Tate, Hongliang Tian
parent cfa6532768
commit de904bf628
53 changed files with 1574 additions and 1730 deletions

@ -0,0 +1,11 @@
use super::*;
pub use self::dev_null::DevNull;
pub use self::dev_random::DevRandom;
pub use self::dev_sgx::DevSgx;
pub use self::dev_zero::DevZero;
mod dev_null;
mod dev_random;
mod dev_sgx;
mod dev_zero;

@ -1,8 +1,4 @@
use super::*; use super::*;
use std;
use std::borrow::BorrowMut;
use std::fmt;
use std::io::SeekFrom;
macro_rules! return_op_unsupported_error { macro_rules! return_op_unsupported_error {
($op_name: expr, $errno: expr) => {{ ($op_name: expr, $errno: expr) => {{
@ -88,436 +84,6 @@ pub trait File: Debug + Sync + Send + Any {
pub type FileRef = Arc<Box<dyn File>>; pub type FileRef = Arc<Box<dyn File>>;
#[derive(Debug)]
#[repr(C)]
pub struct SgxFile {
inner: SgxMutex<SgxFileInner>,
}
impl SgxFile {
pub fn new(
file: Arc<SgxMutex<fs_impl::SgxFile>>,
is_readable: bool,
is_writable: bool,
is_append: bool,
) -> Result<SgxFile> {
if !is_readable && !is_writable {
return_errno!(EINVAL, "Invalid permissions");
}
Ok(SgxFile {
inner: SgxMutex::new(SgxFileInner {
pos: 0 as usize,
file: file,
is_readable,
is_writable,
is_append,
}),
})
}
}
impl File for SgxFile {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut();
inner.read(buf)
}
fn write(&self, buf: &[u8]) -> Result<usize> {
let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut();
inner.write(buf)
}
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut();
inner.seek(SeekFrom::Start(offset as u64))?;
inner.read(buf)
}
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut();
inner.seek(SeekFrom::Start(offset as u64))?;
inner.write(buf)
}
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut();
inner.readv(bufs)
}
fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut();
inner.writev(bufs)
}
fn seek(&self, pos: SeekFrom) -> Result<off_t> {
let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut();
inner.seek(pos)
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[derive(Clone)]
#[repr(C)]
struct SgxFileInner {
// perms: FilePerms,
pos: usize,
file: Arc<SgxMutex<fs_impl::SgxFile>>,
is_readable: bool,
is_writable: bool,
is_append: bool,
}
impl SgxFileInner {
pub fn write(&mut self, buf: &[u8]) -> Result<usize> {
if !self.is_writable {
return_errno!(EINVAL, "File not writable");
}
let mut file_guard = self.file.lock().unwrap();
let file = file_guard.borrow_mut();
let seek_pos = if !self.is_append {
SeekFrom::Start(self.pos as u64)
} else {
SeekFrom::End(0)
};
// TODO: recover from error
file.seek(seek_pos).map_err(|e| errno!(e))?;
let write_len = { file.write(buf).map_err(|e| errno!(e))? };
if !self.is_append {
self.pos += write_len;
}
Ok(write_len)
}
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
if !self.is_readable {
return_errno!(EINVAL, "File not readable");
}
let mut file_guard = self.file.lock().unwrap();
let file = file_guard.borrow_mut();
let seek_pos = SeekFrom::Start(self.pos as u64);
file.seek(seek_pos).map_err(|e| errno!(e))?;
let read_len = { file.read(buf).map_err(|e| errno!(e))? };
self.pos += read_len;
Ok(read_len)
}
pub fn seek(&mut self, pos: SeekFrom) -> Result<off_t> {
let mut file_guard = self.file.lock().unwrap();
let file = file_guard.borrow_mut();
let pos = match pos {
SeekFrom::Start(absolute_offset) => pos,
SeekFrom::End(relative_offset) => pos,
SeekFrom::Current(relative_offset) => {
if relative_offset >= 0 {
SeekFrom::Start((self.pos + relative_offset as usize) as u64)
} else {
let backward_offset = (-relative_offset) as usize;
if self.pos < backward_offset {
// underflow
return_errno!(EINVAL, "Invalid seek position");
}
SeekFrom::Start((self.pos - backward_offset) as u64)
}
}
};
self.pos = file.seek(pos).map_err(|e| errno!(e))? as usize;
Ok(self.pos as off_t)
}
pub fn writev(&mut self, bufs: &[&[u8]]) -> Result<usize> {
if !self.is_writable {
return_errno!(EINVAL, "File not writable");
}
let mut file_guard = self.file.lock().unwrap();
let file = file_guard.borrow_mut();
let seek_pos = if !self.is_append {
SeekFrom::Start(self.pos as u64)
} else {
SeekFrom::End(0)
};
file.seek(seek_pos).map_err(|e| errno!(e))?;
let mut total_bytes = 0;
for buf in bufs {
match file.write(buf) {
Ok(this_bytes) => {
total_bytes += this_bytes;
if this_bytes < buf.len() {
break;
}
}
Err(e) => {
match total_bytes {
// a complete failure
0 => return_errno!(EINVAL, "Failed to write"),
// a partially failure
_ => break,
}
}
}
}
self.pos += total_bytes;
Ok(total_bytes)
}
fn readv(&mut self, bufs: &mut [&mut [u8]]) -> Result<usize> {
if !self.is_readable {
return_errno!(EINVAL, "File not readable");
}
let mut file_guard = self.file.lock().unwrap();
let file = file_guard.borrow_mut();
let seek_pos = SeekFrom::Start(self.pos as u64);
file.seek(seek_pos).map_err(|e| errno!(e))?;
let mut total_bytes = 0;
for buf in bufs {
match file.read(buf) {
Ok(this_bytes) => {
total_bytes += this_bytes;
if this_bytes < buf.len() {
break;
}
}
Err(e) => {
match total_bytes {
// a complete failure
0 => return_errno!(EINVAL, "Failed to write"),
// a partially failure
_ => break,
}
}
}
}
self.pos += total_bytes;
Ok(total_bytes)
}
}
unsafe impl Send for SgxFileInner {}
unsafe impl Sync for SgxFileInner {}
impl Debug for SgxFileInner {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "SgxFileInner {{ pos: {}, file: ??? }}", self.pos)
}
}
pub struct StdoutFile {
inner: std::io::Stdout,
}
impl StdoutFile {
pub fn new() -> StdoutFile {
StdoutFile {
inner: std::io::stdout(),
}
}
}
impl File for StdoutFile {
fn write(&self, buf: &[u8]) -> Result<usize> {
let write_len = { self.inner.lock().write(buf).map_err(|e| errno!(e))? };
Ok(write_len)
}
fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize> {
self.write(buf)
}
fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
let mut guard = self.inner.lock();
let mut total_bytes = 0;
for buf in bufs {
match guard.write(buf) {
Ok(this_len) => {
total_bytes += this_len;
if this_len < buf.len() {
break;
}
}
Err(e) => {
match total_bytes {
// a complete failure
0 => return_errno!(EINVAL, "Failed to write"),
// a partially failure
_ => break,
}
}
}
}
Ok(total_bytes)
}
fn metadata(&self) -> Result<Metadata> {
Ok(Metadata {
dev: 0,
inode: 0,
size: 0,
blk_size: 0,
blocks: 0,
atime: Timespec { sec: 0, nsec: 0 },
mtime: Timespec { sec: 0, nsec: 0 },
ctime: Timespec { sec: 0, nsec: 0 },
type_: FileType::CharDevice,
mode: 0,
nlinks: 0,
uid: 0,
gid: 0,
rdev: 0,
})
}
fn sync_all(&self) -> Result<()> {
self.sync_data()
}
fn sync_data(&self) -> Result<()> {
self.inner.lock().flush()?;
Ok(())
}
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<()> {
let can_delegate_to_host = match cmd {
IoctlCmd::TIOCGWINSZ(_) => true,
IoctlCmd::TIOCSWINSZ(_) => true,
_ => false,
};
if !can_delegate_to_host {
return_errno!(EINVAL, "unknown ioctl cmd for stdout");
}
let cmd_bits = cmd.cmd_num() as c_int;
let cmd_arg_ptr = cmd.arg_ptr() as *const c_int;
let host_stdout_fd = {
use std::os::unix::io::AsRawFd;
self.inner.as_raw_fd() as i32
};
try_libc!(libc::ocall::ioctl_arg1(
host_stdout_fd,
cmd_bits,
cmd_arg_ptr
));
cmd.validate_arg_val()?;
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl Debug for StdoutFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "StdoutFile")
}
}
unsafe impl Send for StdoutFile {}
unsafe impl Sync for StdoutFile {}
pub struct StdinFile {
inner: std::io::Stdin,
}
impl StdinFile {
pub fn new() -> StdinFile {
StdinFile {
inner: std::io::stdin(),
}
}
}
impl File for StdinFile {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
let read_len = { self.inner.lock().read(buf).map_err(|e| errno!(e))? };
Ok(read_len)
}
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
let mut guard = self.inner.lock();
let mut total_bytes = 0;
for buf in bufs {
match guard.read(buf) {
Ok(this_len) => {
total_bytes += this_len;
if this_len < buf.len() {
break;
}
}
Err(e) => {
match total_bytes {
// a complete failure
0 => return_errno!(EINVAL, "Failed to write"),
// a partially failure
_ => break,
}
}
}
}
Ok(total_bytes)
}
fn metadata(&self) -> Result<Metadata> {
Ok(Metadata {
dev: 0,
inode: 0,
size: 0,
blk_size: 0,
blocks: 0,
atime: Timespec { sec: 0, nsec: 0 },
mtime: Timespec { sec: 0, nsec: 0 },
ctime: Timespec { sec: 0, nsec: 0 },
type_: FileType::CharDevice,
mode: 0,
nlinks: 0,
uid: 0,
gid: 0,
rdev: 0,
})
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl Debug for StdinFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "StdinFile")
}
}
unsafe impl Send for StdinFile {}
unsafe impl Sync for StdinFile {}
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
struct FileOpNotSupportedError { struct FileOpNotSupportedError {
errno: Errno, errno: Errno,

@ -1,32 +1,29 @@
use super::*; use super::*;
//int faccessat(int dirfd, const char *pathname, int mode, int flags);
//int access(const char *pathname, int mode);
bitflags! { bitflags! {
pub struct AccessModes : u32 { pub struct AccessibilityCheckMode : u32 {
const X_OK = 1; const X_OK = 1;
const W_OK = 2; const W_OK = 2;
const R_OK = 4; const R_OK = 4;
} }
} }
impl AccessModes { impl AccessibilityCheckMode {
pub fn from_u32(bits: u32) -> Result<AccessModes> { pub fn from_u32(bits: u32) -> Result<AccessibilityCheckMode> {
AccessModes::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid mode")) AccessibilityCheckMode::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid mode"))
} }
} }
bitflags! { bitflags! {
pub struct AccessFlags : u32 { pub struct AccessibilityCheckFlags : u32 {
const AT_SYMLINK_NOFOLLOW = 0x100; const AT_SYMLINK_NOFOLLOW = 0x100;
const AT_EACCESS = 0x200; const AT_EACCESS = 0x200;
} }
} }
impl AccessFlags { impl AccessibilityCheckFlags {
pub fn from_u32(bits: u32) -> Result<AccessFlags> { pub fn from_u32(bits: u32) -> Result<AccessibilityCheckFlags> {
AccessFlags::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid flags")) AccessibilityCheckFlags::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid flags"))
} }
} }
@ -35,8 +32,8 @@ pub const AT_FDCWD: i32 = -100;
pub fn do_faccessat( pub fn do_faccessat(
dirfd: Option<FileDesc>, dirfd: Option<FileDesc>,
path: &str, path: &str,
mode: AccessModes, mode: AccessibilityCheckMode,
flags: AccessFlags, flags: AccessibilityCheckFlags,
) -> Result<()> { ) -> Result<()> {
info!( info!(
"faccessat: dirfd: {:?}, path: {:?}, mode: {:?}, flags: {:?}", "faccessat: dirfd: {:?}, path: {:?}, mode: {:?}, flags: {:?}",
@ -49,7 +46,7 @@ pub fn do_faccessat(
} }
} }
pub fn do_access(path: &str, mode: AccessModes) -> Result<()> { pub fn do_access(path: &str, mode: AccessibilityCheckMode) -> Result<()> {
info!("access: path: {:?}, mode: {:?}", path, mode); info!("access: path: {:?}, mode: {:?}", path, mode);
let current_ref = process::get_current(); let current_ref = process::get_current();
let mut current = current_ref.lock().unwrap(); let mut current = current_ref.lock().unwrap();

@ -0,0 +1,15 @@
use super::*;
pub fn do_chdir(path: &str) -> Result<()> {
let current_ref = process::get_current();
let mut current_process = current_ref.lock().unwrap();
info!("chdir: path: {:?}", path);
let inode = current_process.lookup_inode(path)?;
let info = inode.metadata()?;
if info.type_ != FileType::Dir {
return_errno!(ENOTDIR, "");
}
current_process.change_cwd(path);
Ok(())
}

@ -0,0 +1,11 @@
use super::*;
pub fn do_close(fd: FileDesc) -> Result<()> {
info!("close: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_table_ref = current_process.get_files();
let mut file_table = file_table_ref.lock().unwrap();
file_table.del(fd)?;
Ok(())
}

@ -0,0 +1,100 @@
use super::*;
#[repr(packed)] // Don't use 'C'. Or its size will align up to 8 bytes.
struct LinuxDirent64 {
/// Inode number
ino: u64,
/// Offset to next structure
offset: u64,
/// Size of this dirent
reclen: u16,
/// File type
type_: u8,
/// Filename (null-terminated)
name: [u8; 0],
}
struct DirentBufWriter<'a> {
buf: &'a mut [u8],
rest_size: usize,
written_size: usize,
}
impl<'a> DirentBufWriter<'a> {
unsafe fn new(buf: &'a mut [u8]) -> Self {
let rest_size = buf.len();
DirentBufWriter {
buf,
rest_size,
written_size: 0,
}
}
fn try_write(&mut self, inode: u64, type_: u8, name: &str) -> Result<()> {
let len = ::core::mem::size_of::<LinuxDirent64>() + name.len() + 1;
let len = (len + 7) / 8 * 8; // align up
if self.rest_size < len {
return_errno!(EINVAL, "the given buffer is too small");
}
let dent = LinuxDirent64 {
ino: inode,
offset: 0,
reclen: len as u16,
type_,
name: [],
};
unsafe {
let ptr = self.buf.as_mut_ptr().add(self.written_size) as *mut LinuxDirent64;
ptr.write(dent);
let name_ptr = ptr.add(1) as _;
write_cstr(name_ptr, name);
}
self.rest_size -= len;
self.written_size += len;
Ok(())
}
}
/// Write a Rust string to C string
unsafe fn write_cstr(ptr: *mut u8, s: &str) {
ptr.copy_from(s.as_ptr(), s.len());
ptr.add(s.len()).write(0);
}
pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
info!(
"getdents64: fd: {}, buf: {:?}, buf_size: {}",
fd,
buf.as_ptr(),
buf.len()
);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
let info = file_ref.metadata()?;
if info.type_ != FileType::Dir {
return_errno!(ENOTDIR, "");
}
let mut writer = unsafe { DirentBufWriter::new(buf) };
loop {
let name = match file_ref.read_entry() {
Err(e) => {
let errno = e.errno();
if errno == ENOENT {
break;
}
return Err(e.cause_err(|_| errno!(errno, "failed to read entry")));
}
Ok(name) => name,
};
// TODO: get ino from dirent
if let Err(e) = writer.try_write(0, 0, &name) {
file_ref.seek(SeekFrom::Current(-1))?;
if writer.written_size == 0 {
return Err(e);
} else {
break;
}
}
}
Ok(writer.written_size)
}

@ -0,0 +1,37 @@
use super::*;
pub fn do_dup(old_fd: FileDesc) -> Result<FileDesc> {
let current_ref = process::get_current();
let current = current_ref.lock().unwrap();
let file_table_ref = current.get_files();
let mut file_table = file_table_ref.lock().unwrap();
let file = file_table.get(old_fd)?;
let new_fd = file_table.put(file, false);
Ok(new_fd)
}
pub fn do_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result<FileDesc> {
let current_ref = process::get_current();
let current = current_ref.lock().unwrap();
let file_table_ref = current.get_files();
let mut file_table = file_table_ref.lock().unwrap();
let file = file_table.get(old_fd)?;
if old_fd != new_fd {
file_table.put_at(new_fd, file, false);
}
Ok(new_fd)
}
pub fn do_dup3(old_fd: FileDesc, new_fd: FileDesc, flags: u32) -> Result<FileDesc> {
let creation_flags = CreationFlags::from_bits_truncate(flags);
let current_ref = process::get_current();
let current = current_ref.lock().unwrap();
let file_table_ref = current.get_files();
let mut file_table = file_table_ref.lock().unwrap();
let file = file_table.get(old_fd)?;
if old_fd == new_fd {
return_errno!(EINVAL, "old_fd must not be equal to new_fd");
}
file_table.put_at(new_fd, file, creation_flags.must_close_on_spawn());
Ok(new_fd)
}

@ -1,5 +1,4 @@
use super::*; use super::*;
use process::FileTableRef;
#[derive(Debug)] #[derive(Debug)]
pub enum FcntlCmd { pub enum FcntlCmd {
@ -34,7 +33,11 @@ impl FcntlCmd {
} }
} }
pub fn do_fcntl(file_table_ref: &FileTableRef, fd: FileDesc, cmd: &FcntlCmd) -> Result<isize> { pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result<isize> {
info!("fcntl: fd: {:?}, cmd: {:?}", &fd, cmd);
let current_ref = process::get_current();
let mut current = current_ref.lock().unwrap();
let file_table_ref = current.get_files();
let mut file_table = file_table_ref.lock().unwrap(); let mut file_table = file_table_ref.lock().unwrap();
let ret = match cmd { let ret = match cmd {
FcntlCmd::DupFd(min_fd) => { FcntlCmd::DupFd(min_fd) => {

@ -0,0 +1,19 @@
use super::*;
pub fn do_fsync(fd: FileDesc) -> Result<()> {
info!("fsync: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.sync_all()?;
Ok(())
}
pub fn do_fdatasync(fd: FileDesc) -> Result<()> {
info!("fdatasync: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.sync_data()?;
Ok(())
}

@ -63,3 +63,11 @@ impl<'a> IoctlCmd<'a> {
Ok(()) Ok(())
} }
} }
pub fn do_ioctl(fd: FileDesc, cmd: &mut IoctlCmd) -> Result<()> {
info!("ioctl: fd: {}, cmd: {:?}", fd, cmd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.ioctl(cmd)
}

@ -0,0 +1,13 @@
use super::*;
pub fn do_link(oldpath: &str, newpath: &str) -> Result<()> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
info!("link: oldpath: {:?}, newpath: {:?}", oldpath, newpath);
let (new_dir_path, new_file_name) = split_path(&newpath);
let inode = current_process.lookup_inode(&oldpath)?;
let new_dir_inode = current_process.lookup_inode(new_dir_path)?;
new_dir_inode.link(new_file_name, &inode)?;
Ok(())
}

@ -0,0 +1,8 @@
use super::*;
pub fn do_lseek(fd: FileDesc, offset: SeekFrom) -> Result<off_t> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.seek(offset)
}

@ -0,0 +1,19 @@
use super::*;
pub fn do_mkdir(path: &str, mode: usize) -> Result<()> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
// TODO: check pathname
info!("mkdir: path: {:?}, mode: {:#o}", path, mode);
let (dir_path, file_name) = split_path(&path);
let inode = current_process.lookup_inode(dir_path)?;
if inode.find(file_name).is_ok() {
return_errno!(EEXIST, "");
}
if !inode.allow_write()? {
return_errno!(EPERM, "dir cannot be written");
}
inode.create(file_name, FileType::Dir, mode as u32)?;
Ok(())
}

@ -0,0 +1,141 @@
use super::dev_fs::{DevNull, DevRandom, DevSgx, DevZero};
use super::*;
use process::Process;
pub use self::access::{
do_access, do_faccessat, AccessibilityCheckFlags, AccessibilityCheckMode, AT_FDCWD,
};
pub use self::chdir::do_chdir;
pub use self::close::do_close;
pub use self::dirent::do_getdents64;
pub use self::dup::{do_dup, do_dup2, do_dup3};
pub use self::fcntl::{do_fcntl, FcntlCmd};
pub use self::file_flags::{AccessMode, CreationFlags, StatusFlags};
pub use self::fsync::{do_fdatasync, do_fsync};
pub use self::ioctl::{do_ioctl, IoctlCmd, StructuredIoctlArgType, StructuredIoctlNum};
pub use self::link::do_link;
pub use self::lseek::do_lseek;
pub use self::mkdir::do_mkdir;
pub use self::open::do_open;
pub use self::read::{do_pread, do_read, do_readv};
pub use self::rename::do_rename;
pub use self::rmdir::do_rmdir;
pub use self::sendfile::do_sendfile;
pub use self::stat::{do_fstat, do_lstat, do_stat, Stat};
pub use self::symlink::do_readlink;
pub use self::truncate::{do_ftruncate, do_truncate};
pub use self::unlink::do_unlink;
pub use self::write::{do_pwrite, do_write, do_writev};
mod access;
mod chdir;
mod close;
mod dirent;
mod dup;
mod fcntl;
mod file_flags;
mod fsync;
mod ioctl;
mod link;
mod lseek;
mod mkdir;
mod open;
mod read;
mod rename;
mod rmdir;
mod sendfile;
mod stat;
mod symlink;
mod truncate;
mod unlink;
mod write;
impl Process {
/// Open a file on the process. But DO NOT add it to file table.
pub fn open_file(&self, path: &str, flags: u32, mode: u32) -> Result<Box<dyn File>> {
if path == "/dev/null" {
return Ok(Box::new(DevNull));
}
if path == "/dev/zero" {
return Ok(Box::new(DevZero));
}
if path == "/dev/random" || path == "/dev/urandom" || path == "/dev/arandom" {
return Ok(Box::new(DevRandom));
}
if path == "/dev/sgx" {
return Ok(Box::new(DevSgx));
}
let creation_flags = CreationFlags::from_bits_truncate(flags);
let inode = if creation_flags.can_create() {
let (dir_path, file_name) = split_path(&path);
let dir_inode = self.lookup_inode(dir_path)?;
match dir_inode.find(file_name) {
Ok(file_inode) => {
if creation_flags.is_exclusive() {
return_errno!(EEXIST, "file exists");
}
file_inode
}
Err(FsError::EntryNotFound) => {
if !dir_inode.allow_write()? {
return_errno!(EPERM, "file cannot be created");
}
dir_inode.create(file_name, FileType::File, mode)?
}
Err(e) => return Err(Error::from(e)),
}
} else {
self.lookup_inode(&path)?
};
let abs_path = self.convert_to_abs_path(&path);
Ok(Box::new(INodeFile::open(inode, &abs_path, flags)?))
}
/// Lookup INode from the cwd of the process
pub fn lookup_inode(&self, path: &str) -> Result<Arc<dyn INode>> {
debug!("lookup_inode: cwd: {:?}, path: {:?}", self.get_cwd(), path);
if path.len() > 0 && path.as_bytes()[0] == b'/' {
// absolute path
let abs_path = path.trim_start_matches('/');
let inode = ROOT_INODE.lookup(abs_path)?;
Ok(inode)
} else {
// relative path
let cwd = self.get_cwd().trim_start_matches('/');
let inode = ROOT_INODE.lookup(cwd)?.lookup(path)?;
Ok(inode)
}
}
/// Convert the path to be absolute
pub fn convert_to_abs_path(&self, path: &str) -> String {
debug!(
"convert_to_abs_path: cwd: {:?}, path: {:?}",
self.get_cwd(),
path
);
if path.len() > 0 && path.as_bytes()[0] == b'/' {
// path is absolute path already
return path.to_owned();
}
let cwd = {
if !self.get_cwd().ends_with("/") {
self.get_cwd().to_owned() + "/"
} else {
self.get_cwd().to_owned()
}
};
cwd + path
}
}
/// Split a `path` str to `(base_path, file_name)`
pub fn split_path(path: &str) -> (&str, &str) {
let mut split = path.trim_end_matches('/').rsplitn(2, '/');
let file_name = split.next().unwrap();
let mut dir_path = split.next().unwrap_or(".");
if dir_path == "" {
dir_path = "/";
}
(dir_path, file_name)
}

@ -0,0 +1,23 @@
use super::*;
pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc> {
info!(
"open: path: {:?}, flags: {:#o}, mode: {:#o}",
path, flags, mode
);
let current_ref = process::get_current();
let mut proc = current_ref.lock().unwrap();
let file = proc.open_file(path, flags, mode)?;
let file_ref: Arc<Box<dyn File>> = Arc::new(file);
let fd = {
let creation_flags = CreationFlags::from_bits_truncate(flags);
proc.get_files()
.lock()
.unwrap()
.put(file_ref, creation_flags.must_close_on_spawn())
};
Ok(fd)
}

@ -0,0 +1,25 @@
use super::*;
pub fn do_read(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
info!("read: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.read(buf)
}
pub fn do_readv(fd: FileDesc, bufs: &mut [&mut [u8]]) -> Result<usize> {
info!("readv: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.readv(bufs)
}
pub fn do_pread(fd: FileDesc, buf: &mut [u8], offset: usize) -> Result<usize> {
info!("pread: fd: {}, offset: {}", fd, offset);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.read_at(offset, buf)
}

@ -0,0 +1,15 @@
use super::*;
pub fn do_rename(oldpath: &str, newpath: &str) -> Result<()> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
info!("rename: oldpath: {:?}, newpath: {:?}", oldpath, newpath);
let (old_dir_path, old_file_name) = split_path(&oldpath);
let (new_dir_path, new_file_name) = split_path(&newpath);
let old_dir_inode = current_process.lookup_inode(old_dir_path)?;
let new_dir_inode = current_process.lookup_inode(new_dir_path)?;
// TODO: support to modify file's absolute path
old_dir_inode.move_(old_file_name, &new_dir_inode, new_file_name)?;
Ok(())
}

@ -0,0 +1,16 @@
use super::*;
pub fn do_rmdir(path: &str) -> Result<()> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
info!("rmdir: path: {:?}", path);
let (dir_path, file_name) = split_path(&path);
let dir_inode = current_process.lookup_inode(dir_path)?;
let file_inode = dir_inode.find(file_name)?;
if file_inode.metadata()?.type_ != FileType::Dir {
return_errno!(ENOTDIR, "rmdir on not directory");
}
dir_inode.unlink(file_name)?;
Ok(())
}

@ -0,0 +1,52 @@
use super::*;
pub fn do_sendfile(
out_fd: FileDesc,
in_fd: FileDesc,
offset: Option<off_t>,
count: usize,
) -> Result<(usize, usize)> {
// (len, offset)
info!(
"sendfile: out: {}, in: {}, offset: {:?}, count: {}",
out_fd, in_fd, offset, count
);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_table_ref = current_process.get_files();
let mut file_table = file_table_ref.lock().unwrap();
let in_file = file_table.get(in_fd)?;
let out_file = file_table.get(out_fd)?;
let mut buffer: [u8; 1024 * 11] = unsafe { MaybeUninit::uninit().assume_init() };
let mut read_offset = match offset {
Some(offset) => offset,
None => in_file.seek(SeekFrom::Current(0))?,
} as usize;
// read from specified offset and write new offset back
let mut bytes_read = 0;
while bytes_read < count {
let len = min(buffer.len(), count - bytes_read);
let read_len = in_file.read_at(read_offset, &mut buffer[..len])?;
if read_len == 0 {
break;
}
bytes_read += read_len;
read_offset += read_len;
let mut bytes_written = 0;
while bytes_written < read_len {
let write_len = out_file.write(&buffer[bytes_written..])?;
if write_len == 0 {
return_errno!(EBADF, "sendfile write return 0");
}
bytes_written += write_len;
}
}
if offset.is_none() {
in_file.seek(SeekFrom::Current(bytes_read as i64))?;
}
Ok((bytes_read, read_offset))
}

@ -0,0 +1,151 @@
use super::*;
#[repr(C)]
pub struct Stat {
/// ID of device containing file
dev: u64,
/// inode number
ino: u64,
/// number of hard links
nlink: u64,
/// file type and mode
mode: StatMode,
/// user ID of owner
uid: u32,
/// group ID of owner
gid: u32,
/// padding
_pad0: u32,
/// device ID (if special file)
rdev: u64,
/// total size, in bytes
size: u64,
/// blocksize for filesystem I/O
blksize: u64,
/// number of 512B blocks allocated
blocks: u64,
/// last access time
atime: Timespec,
/// last modification time
mtime: Timespec,
/// last status change time
ctime: Timespec,
}
bitflags! {
pub struct StatMode: u32 {
const NULL = 0;
/// Type
const TYPE_MASK = 0o170000;
/// FIFO
const FIFO = 0o010000;
/// character device
const CHAR = 0o020000;
/// directory
const DIR = 0o040000;
/// block device
const BLOCK = 0o060000;
/// ordinary regular file
const FILE = 0o100000;
/// symbolic link
const LINK = 0o120000;
/// socket
const SOCKET = 0o140000;
/// Set-user-ID on execution.
const SET_UID = 0o4000;
/// Set-group-ID on execution.
const SET_GID = 0o2000;
/// Read, write, execute/search by owner.
const OWNER_MASK = 0o700;
/// Read permission, owner.
const OWNER_READ = 0o400;
/// Write permission, owner.
const OWNER_WRITE = 0o200;
/// Execute/search permission, owner.
const OWNER_EXEC = 0o100;
/// Read, write, execute/search by group.
const GROUP_MASK = 0o70;
/// Read permission, group.
const GROUP_READ = 0o40;
/// Write permission, group.
const GROUP_WRITE = 0o20;
/// Execute/search permission, group.
const GROUP_EXEC = 0o10;
/// Read, write, execute/search by others.
const OTHER_MASK = 0o7;
/// Read permission, others.
const OTHER_READ = 0o4;
/// Write permission, others.
const OTHER_WRITE = 0o2;
/// Execute/search permission, others.
const OTHER_EXEC = 0o1;
}
}
impl StatMode {
fn from_type_mode(type_: FileType, mode: u16) -> Self {
let type_ = match type_ {
FileType::File => StatMode::FILE,
FileType::Dir => StatMode::DIR,
FileType::SymLink => StatMode::LINK,
FileType::CharDevice => StatMode::CHAR,
FileType::BlockDevice => StatMode::BLOCK,
FileType::Socket => StatMode::SOCKET,
FileType::NamedPipe => StatMode::FIFO,
_ => StatMode::NULL,
};
let mode = StatMode::from_bits_truncate(mode as u32);
type_ | mode
}
}
impl From<Metadata> for Stat {
fn from(info: Metadata) -> Self {
Stat {
dev: info.dev as u64,
ino: info.inode as u64,
mode: StatMode::from_type_mode(info.type_, info.mode as u16),
nlink: info.nlinks as u64,
uid: info.uid as u32,
gid: info.gid as u32,
rdev: 0,
size: info.size as u64,
blksize: info.blk_size as u64,
blocks: info.blocks as u64,
atime: info.atime,
mtime: info.mtime,
ctime: info.ctime,
_pad0: 0,
}
}
}
pub fn do_stat(path: &str) -> Result<Stat> {
warn!("stat is partial implemented as lstat");
do_lstat(path)
}
pub fn do_fstat(fd: u32) -> Result<Stat> {
info!("fstat: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
let stat = Stat::from(file_ref.metadata()?);
// TODO: handle symlink
Ok(stat)
}
pub fn do_lstat(path: &str) -> Result<Stat> {
info!("lstat: path: {}", path);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let inode = current_process.lookup_inode(&path)?;
let stat = Stat::from(inode.metadata()?);
Ok(stat)
}

@ -0,0 +1,32 @@
use super::*;
pub fn do_readlink(path: &str, buf: &mut [u8]) -> Result<usize> {
info!("readlink: path: {:?}", path);
let file_path = {
if path == "/proc/self/exe" {
let current_ref = process::get_current();
let current = current_ref.lock().unwrap();
current.get_elf_path().to_owned()
} else if path.starts_with("/proc/self/fd") {
let fd = path
.trim_start_matches("/proc/self/fd/")
.parse::<FileDesc>()
.map_err(|e| errno!(EBADF, "Invalid file descriptor"))?;
let current_ref = process::get_current();
let current = current_ref.lock().unwrap();
let file_ref = current.get_files().lock().unwrap().get(fd)?;
if let Ok(inode_file) = file_ref.as_inode_file() {
inode_file.get_abs_path().to_owned()
} else {
// TODO: support special device files
return_errno!(EINVAL, "not a normal file link")
}
} else {
// TODO: support symbolic links
return_errno!(EINVAL, "not a symbolic link")
}
};
let len = file_path.len().min(buf.len());
buf[0..len].copy_from_slice(&file_path.as_bytes()[0..len]);
Ok(len)
}

@ -0,0 +1,18 @@
use super::*;
pub fn do_truncate(path: &str, len: usize) -> Result<()> {
info!("truncate: path: {:?}, len: {}", path, len);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
current_process.lookup_inode(&path)?.resize(len)?;
Ok(())
}
pub fn do_ftruncate(fd: FileDesc, len: usize) -> Result<()> {
info!("ftruncate: fd: {}, len: {}", fd, len);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.set_len(len as u64)?;
Ok(())
}

@ -0,0 +1,16 @@
use super::*;
pub fn do_unlink(path: &str) -> Result<()> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
info!("unlink: path: {:?}", path);
let (dir_path, file_name) = split_path(&path);
let dir_inode = current_process.lookup_inode(dir_path)?;
let file_inode = dir_inode.find(file_name)?;
if file_inode.metadata()?.type_ == FileType::Dir {
return_errno!(EISDIR, "unlink on directory");
}
dir_inode.unlink(file_name)?;
Ok(())
}

@ -0,0 +1,25 @@
use super::*;
pub fn do_write(fd: FileDesc, buf: &[u8]) -> Result<usize> {
info!("write: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.write(buf)
}
pub fn do_writev(fd: FileDesc, bufs: &[&[u8]]) -> Result<usize> {
info!("writev: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.writev(bufs)
}
pub fn do_pwrite(fd: FileDesc, buf: &[u8], offset: usize) -> Result<usize> {
info!("pwrite: fd: {}, offset: {}", fd, offset);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.write_at(offset, buf)
}

@ -1,6 +1,4 @@
use super::file::{File, FileRef};
use super::*; use super::*;
use std;
pub type FileDesc = u32; pub type FileDesc = u32;

@ -0,0 +1,5 @@
use super::*;
pub use self::sync::do_sync;
mod sync;

@ -0,0 +1,7 @@
use super::*;
pub fn do_sync() -> Result<()> {
info!("sync:");
ROOT_INODE.fs().sync()?;
Ok(())
}

@ -1,7 +1,6 @@
use super::*; use super::*;
use rcore_fs_sefs::dev::SefsMac; use rcore_fs_sefs::dev::SefsMac;
use sgx_trts::libc::S_IRUSR; use sgx_trts::libc::{S_IRUSR, S_IWUSR};
use std::fmt;
pub struct INodeFile { pub struct INodeFile {
inode: Arc<dyn INode>, inode: Arc<dyn INode>,

@ -1,756 +1,32 @@
use super::*; use super::*;
use net::{AsSocket, SocketFile}; use process;
use process::Process; use rcore_fs::vfs::{FileSystem, FileType, FsError, INode, Metadata, Timespec};
use rcore_fs::vfs::{FileType, FsError, INode, Metadata, Timespec}; use std;
use std::io::{Read, Seek, SeekFrom, Write};
use std::sgxfs as fs_impl;
use {process, std};
pub use self::access::{do_access, do_faccessat, AccessFlags, AccessModes, AT_FDCWD};
use self::dev_null::DevNull;
use self::dev_random::DevRandom;
use self::dev_sgx::DevSgx;
use self::dev_zero::DevZero;
pub use self::fcntl::FcntlCmd;
pub use self::file::{File, FileRef, SgxFile, StdinFile, StdoutFile};
pub use self::file_flags::{AccessMode, CreationFlags, StatusFlags};
pub use self::file_table::{FileDesc, FileTable};
pub use self::inode_file::{AsINodeFile, INodeExt, INodeFile};
pub use self::io_multiplexing::*;
pub use self::ioctl::*;
pub use self::pipe::Pipe;
pub use self::root_inode::ROOT_INODE;
pub use self::unix_socket::{AsUnixSocket, UnixSocketFile};
use sgx_trts::libc::S_IWUSR;
use std::any::Any; use std::any::Any;
use std::fmt;
use std::io::{Read, Seek, SeekFrom, Write};
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
mod access; pub use self::file::{File, FileRef};
mod dev_null; pub use self::file_ops::{AccessMode, CreationFlags, Stat, StatusFlags};
mod dev_random; pub use self::file_ops::{IoctlCmd, StructuredIoctlArgType, StructuredIoctlNum};
mod dev_sgx; pub use self::file_table::{FileDesc, FileTable};
mod dev_zero; pub use self::inode_file::{AsINodeFile, INodeExt, INodeFile};
mod fcntl; pub use self::pipe::Pipe;
pub use self::rootfs::ROOT_INODE;
pub use self::stdio::{StdinFile, StdoutFile};
pub use self::syscalls::*;
mod dev_fs;
mod file; mod file;
mod file_flags; mod file_ops;
mod file_table; mod file_table;
mod fs_ops;
mod hostfs; mod hostfs;
mod inode_file; mod inode_file;
mod io_multiplexing;
mod ioctl;
mod pipe; mod pipe;
mod root_inode; mod rootfs;
mod sgx_impl; mod sefs;
mod unix_socket; mod stdio;
mod syscalls;
pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc> {
info!(
"open: path: {:?}, flags: {:#o}, mode: {:#o}",
path, flags, mode
);
let current_ref = process::get_current();
let mut proc = current_ref.lock().unwrap();
let file = proc.open_file(path, flags, mode)?;
let file_ref: Arc<Box<dyn File>> = Arc::new(file);
let fd = {
let creation_flags = CreationFlags::from_bits_truncate(flags);
proc.get_files()
.lock()
.unwrap()
.put(file_ref, creation_flags.must_close_on_spawn())
};
Ok(fd)
}
pub fn do_write(fd: FileDesc, buf: &[u8]) -> Result<usize> {
info!("write: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.write(buf)
}
pub fn do_read(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
info!("read: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.read(buf)
}
pub fn do_writev(fd: FileDesc, bufs: &[&[u8]]) -> Result<usize> {
info!("writev: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.writev(bufs)
}
pub fn do_readv(fd: FileDesc, bufs: &mut [&mut [u8]]) -> Result<usize> {
info!("readv: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.readv(bufs)
}
pub fn do_pwrite(fd: FileDesc, buf: &[u8], offset: usize) -> Result<usize> {
info!("pwrite: fd: {}, offset: {}", fd, offset);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.write_at(offset, buf)
}
pub fn do_pread(fd: FileDesc, buf: &mut [u8], offset: usize) -> Result<usize> {
info!("pread: fd: {}, offset: {}", fd, offset);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.read_at(offset, buf)
}
pub fn do_stat(path: &str) -> Result<Stat> {
warn!("stat is partial implemented as lstat");
do_lstat(path)
}
pub fn do_fstat(fd: u32) -> Result<Stat> {
info!("fstat: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
let stat = Stat::from(file_ref.metadata()?);
// TODO: handle symlink
Ok(stat)
}
pub fn do_lstat(path: &str) -> Result<Stat> {
info!("lstat: path: {}", path);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let inode = current_process.lookup_inode(&path)?;
let stat = Stat::from(inode.metadata()?);
Ok(stat)
}
pub fn do_lseek(fd: FileDesc, offset: SeekFrom) -> Result<off_t> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.seek(offset)
}
pub fn do_fsync(fd: FileDesc) -> Result<()> {
info!("fsync: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.sync_all()?;
Ok(())
}
pub fn do_fdatasync(fd: FileDesc) -> Result<()> {
info!("fdatasync: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.sync_data()?;
Ok(())
}
pub fn do_truncate(path: &str, len: usize) -> Result<()> {
info!("truncate: path: {:?}, len: {}", path, len);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
current_process.lookup_inode(&path)?.resize(len)?;
Ok(())
}
pub fn do_ftruncate(fd: FileDesc, len: usize) -> Result<()> {
info!("ftruncate: fd: {}, len: {}", fd, len);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.set_len(len as u64)?;
Ok(())
}
pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
info!(
"getdents64: fd: {}, buf: {:?}, buf_size: {}",
fd,
buf.as_ptr(),
buf.len()
);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
let info = file_ref.metadata()?;
if info.type_ != FileType::Dir {
return_errno!(ENOTDIR, "");
}
let mut writer = unsafe { DirentBufWriter::new(buf) };
loop {
let name = match file_ref.read_entry() {
Err(e) => {
let errno = e.errno();
if errno == ENOENT {
break;
}
return Err(e.cause_err(|_| errno!(errno, "failed to read entry")));
}
Ok(name) => name,
};
// TODO: get ino from dirent
if let Err(e) = writer.try_write(0, 0, &name) {
file_ref.seek(SeekFrom::Current(-1))?;
if writer.written_size == 0 {
return Err(e);
} else {
break;
}
}
}
Ok(writer.written_size)
}
pub fn do_close(fd: FileDesc) -> Result<()> {
info!("close: fd: {}", fd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_table_ref = current_process.get_files();
let mut file_table = file_table_ref.lock().unwrap();
file_table.del(fd)?;
Ok(())
}
pub fn do_ioctl(fd: FileDesc, cmd: &mut IoctlCmd) -> Result<()> {
info!("ioctl: fd: {}, cmd: {:?}", fd, cmd);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
file_ref.ioctl(cmd)
}
pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2]> {
info!("pipe2: flags: {:#x}", flags);
let creation_flags = CreationFlags::from_bits_truncate(flags);
let current_ref = process::get_current();
let current = current_ref.lock().unwrap();
let pipe = Pipe::new(StatusFlags::from_bits_truncate(flags))?;
let file_table_ref = current.get_files();
let mut file_table = file_table_ref.lock().unwrap();
let close_on_spawn = creation_flags.must_close_on_spawn();
let reader_fd = file_table.put(Arc::new(Box::new(pipe.reader)), close_on_spawn);
let writer_fd = file_table.put(Arc::new(Box::new(pipe.writer)), close_on_spawn);
info!("pipe2: reader_fd: {}, writer_fd: {}", reader_fd, writer_fd);
Ok([reader_fd, writer_fd])
}
pub fn do_dup(old_fd: FileDesc) -> Result<FileDesc> {
let current_ref = process::get_current();
let current = current_ref.lock().unwrap();
let file_table_ref = current.get_files();
let mut file_table = file_table_ref.lock().unwrap();
let file = file_table.get(old_fd)?;
let new_fd = file_table.put(file, false);
Ok(new_fd)
}
pub fn do_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result<FileDesc> {
let current_ref = process::get_current();
let current = current_ref.lock().unwrap();
let file_table_ref = current.get_files();
let mut file_table = file_table_ref.lock().unwrap();
let file = file_table.get(old_fd)?;
if old_fd != new_fd {
file_table.put_at(new_fd, file, false);
}
Ok(new_fd)
}
pub fn do_dup3(old_fd: FileDesc, new_fd: FileDesc, flags: u32) -> Result<FileDesc> {
let creation_flags = CreationFlags::from_bits_truncate(flags);
let current_ref = process::get_current();
let current = current_ref.lock().unwrap();
let file_table_ref = current.get_files();
let mut file_table = file_table_ref.lock().unwrap();
let file = file_table.get(old_fd)?;
if old_fd == new_fd {
return_errno!(EINVAL, "old_fd must not be equal to new_fd");
}
file_table.put_at(new_fd, file, creation_flags.must_close_on_spawn());
Ok(new_fd)
}
pub fn do_sync() -> Result<()> {
info!("sync:");
ROOT_INODE.fs().sync()?;
Ok(())
}
pub fn do_chdir(path: &str) -> Result<()> {
let current_ref = process::get_current();
let mut current_process = current_ref.lock().unwrap();
info!("chdir: path: {:?}", path);
let inode = current_process.lookup_inode(path)?;
let info = inode.metadata()?;
if info.type_ != FileType::Dir {
return_errno!(ENOTDIR, "");
}
current_process.change_cwd(path);
Ok(())
}
pub fn do_rename(oldpath: &str, newpath: &str) -> Result<()> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
info!("rename: oldpath: {:?}, newpath: {:?}", oldpath, newpath);
let (old_dir_path, old_file_name) = split_path(&oldpath);
let (new_dir_path, new_file_name) = split_path(&newpath);
let old_dir_inode = current_process.lookup_inode(old_dir_path)?;
let new_dir_inode = current_process.lookup_inode(new_dir_path)?;
// TODO: support to modify file's absolute path
old_dir_inode.move_(old_file_name, &new_dir_inode, new_file_name)?;
Ok(())
}
pub fn do_mkdir(path: &str, mode: usize) -> Result<()> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
// TODO: check pathname
info!("mkdir: path: {:?}, mode: {:#o}", path, mode);
let (dir_path, file_name) = split_path(&path);
let inode = current_process.lookup_inode(dir_path)?;
if inode.find(file_name).is_ok() {
return_errno!(EEXIST, "");
}
if !inode.allow_write()? {
return_errno!(EPERM, "dir cannot be written");
}
inode.create(file_name, FileType::Dir, mode as u32)?;
Ok(())
}
pub fn do_rmdir(path: &str) -> Result<()> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
info!("rmdir: path: {:?}", path);
let (dir_path, file_name) = split_path(&path);
let dir_inode = current_process.lookup_inode(dir_path)?;
let file_inode = dir_inode.find(file_name)?;
if file_inode.metadata()?.type_ != FileType::Dir {
return_errno!(ENOTDIR, "rmdir on not directory");
}
dir_inode.unlink(file_name)?;
Ok(())
}
pub fn do_link(oldpath: &str, newpath: &str) -> Result<()> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
info!("link: oldpath: {:?}, newpath: {:?}", oldpath, newpath);
let (new_dir_path, new_file_name) = split_path(&newpath);
let inode = current_process.lookup_inode(&oldpath)?;
let new_dir_inode = current_process.lookup_inode(new_dir_path)?;
new_dir_inode.link(new_file_name, &inode)?;
Ok(())
}
pub fn do_unlink(path: &str) -> Result<()> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
info!("unlink: path: {:?}", path);
let (dir_path, file_name) = split_path(&path);
let dir_inode = current_process.lookup_inode(dir_path)?;
let file_inode = dir_inode.find(file_name)?;
if file_inode.metadata()?.type_ == FileType::Dir {
return_errno!(EISDIR, "unlink on directory");
}
dir_inode.unlink(file_name)?;
Ok(())
}
pub fn do_sendfile(
out_fd: FileDesc,
in_fd: FileDesc,
offset: Option<off_t>,
count: usize,
) -> Result<(usize, usize)> {
// (len, offset)
info!(
"sendfile: out: {}, in: {}, offset: {:?}, count: {}",
out_fd, in_fd, offset, count
);
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_table_ref = current_process.get_files();
let mut file_table = file_table_ref.lock().unwrap();
let in_file = file_table.get(in_fd)?;
let out_file = file_table.get(out_fd)?;
let mut buffer: [u8; 1024 * 11] = unsafe { MaybeUninit::uninit().assume_init() };
let mut read_offset = match offset {
Some(offset) => offset,
None => in_file.seek(SeekFrom::Current(0))?,
} as usize;
// read from specified offset and write new offset back
let mut bytes_read = 0;
while bytes_read < count {
let len = min(buffer.len(), count - bytes_read);
let read_len = in_file.read_at(read_offset, &mut buffer[..len])?;
if read_len == 0 {
break;
}
bytes_read += read_len;
read_offset += read_len;
let mut bytes_written = 0;
while bytes_written < read_len {
let write_len = out_file.write(&buffer[bytes_written..])?;
if write_len == 0 {
return_errno!(EBADF, "sendfile write return 0");
}
bytes_written += write_len;
}
}
if offset.is_none() {
in_file.seek(SeekFrom::Current(bytes_read as i64))?;
}
Ok((bytes_read, read_offset))
}
extern "C" {
fn occlum_ocall_sync() -> sgx_status_t;
}
impl Process {
/// Open a file on the process. But DO NOT add it to file table.
pub fn open_file(&self, path: &str, flags: u32, mode: u32) -> Result<Box<dyn File>> {
if path == "/dev/null" {
return Ok(Box::new(DevNull));
}
if path == "/dev/zero" {
return Ok(Box::new(DevZero));
}
if path == "/dev/random" || path == "/dev/urandom" || path == "/dev/arandom" {
return Ok(Box::new(DevRandom));
}
if path == "/dev/sgx" {
return Ok(Box::new(DevSgx));
}
let creation_flags = CreationFlags::from_bits_truncate(flags);
let inode = if creation_flags.can_create() {
let (dir_path, file_name) = split_path(&path);
let dir_inode = self.lookup_inode(dir_path)?;
match dir_inode.find(file_name) {
Ok(file_inode) => {
if creation_flags.is_exclusive() {
return_errno!(EEXIST, "file exists");
}
file_inode
}
Err(FsError::EntryNotFound) => {
if !dir_inode.allow_write()? {
return_errno!(EPERM, "file cannot be created");
}
dir_inode.create(file_name, FileType::File, mode)?
}
Err(e) => return Err(Error::from(e)),
}
} else {
self.lookup_inode(&path)?
};
let abs_path = self.convert_to_abs_path(&path);
Ok(Box::new(INodeFile::open(inode, &abs_path, flags)?))
}
/// Lookup INode from the cwd of the process
pub fn lookup_inode(&self, path: &str) -> Result<Arc<dyn INode>> {
debug!("lookup_inode: cwd: {:?}, path: {:?}", self.get_cwd(), path);
if path.len() > 0 && path.as_bytes()[0] == b'/' {
// absolute path
let abs_path = path.trim_start_matches('/');
let inode = ROOT_INODE.lookup(abs_path)?;
Ok(inode)
} else {
// relative path
let cwd = self.get_cwd().trim_start_matches('/');
let inode = ROOT_INODE.lookup(cwd)?.lookup(path)?;
Ok(inode)
}
}
/// Convert the path to be absolute
pub fn convert_to_abs_path(&self, path: &str) -> String {
debug!(
"convert_to_abs_path: cwd: {:?}, path: {:?}",
self.get_cwd(),
path
);
if path.len() > 0 && path.as_bytes()[0] == b'/' {
// path is absolute path already
return path.to_owned();
}
let cwd = {
if !self.get_cwd().ends_with("/") {
self.get_cwd().to_owned() + "/"
} else {
self.get_cwd().to_owned()
}
};
cwd + path
}
}
/// Split a `path` str to `(base_path, file_name)`
fn split_path(path: &str) -> (&str, &str) {
let mut split = path.trim_end_matches('/').rsplitn(2, '/');
let file_name = split.next().unwrap();
let mut dir_path = split.next().unwrap_or(".");
if dir_path == "" {
dir_path = "/";
}
(dir_path, file_name)
}
#[repr(packed)] // Don't use 'C'. Or its size will align up to 8 bytes.
pub struct LinuxDirent64 {
/// Inode number
ino: u64,
/// Offset to next structure
offset: u64,
/// Size of this dirent
reclen: u16,
/// File type
type_: u8,
/// Filename (null-terminated)
name: [u8; 0],
}
struct DirentBufWriter<'a> {
buf: &'a mut [u8],
rest_size: usize,
written_size: usize,
}
impl<'a> DirentBufWriter<'a> {
unsafe fn new(buf: &'a mut [u8]) -> Self {
let rest_size = buf.len();
DirentBufWriter {
buf,
rest_size,
written_size: 0,
}
}
fn try_write(&mut self, inode: u64, type_: u8, name: &str) -> Result<()> {
let len = ::core::mem::size_of::<LinuxDirent64>() + name.len() + 1;
let len = (len + 7) / 8 * 8; // align up
if self.rest_size < len {
return_errno!(EINVAL, "the given buffer is too small");
}
let dent = LinuxDirent64 {
ino: inode,
offset: 0,
reclen: len as u16,
type_,
name: [],
};
unsafe {
let ptr = self.buf.as_mut_ptr().add(self.written_size) as *mut LinuxDirent64;
ptr.write(dent);
let name_ptr = ptr.add(1) as _;
write_cstr(name_ptr, name);
}
self.rest_size -= len;
self.written_size += len;
Ok(())
}
}
#[repr(C)]
pub struct Stat {
/// ID of device containing file
dev: u64,
/// inode number
ino: u64,
/// number of hard links
nlink: u64,
/// file type and mode
mode: StatMode,
/// user ID of owner
uid: u32,
/// group ID of owner
gid: u32,
/// padding
_pad0: u32,
/// device ID (if special file)
rdev: u64,
/// total size, in bytes
size: u64,
/// blocksize for filesystem I/O
blksize: u64,
/// number of 512B blocks allocated
blocks: u64,
/// last access time
atime: Timespec,
/// last modification time
mtime: Timespec,
/// last status change time
ctime: Timespec,
}
bitflags! {
pub struct StatMode: u32 {
const NULL = 0;
/// Type
const TYPE_MASK = 0o170000;
/// FIFO
const FIFO = 0o010000;
/// character device
const CHAR = 0o020000;
/// directory
const DIR = 0o040000;
/// block device
const BLOCK = 0o060000;
/// ordinary regular file
const FILE = 0o100000;
/// symbolic link
const LINK = 0o120000;
/// socket
const SOCKET = 0o140000;
/// Set-user-ID on execution.
const SET_UID = 0o4000;
/// Set-group-ID on execution.
const SET_GID = 0o2000;
/// Read, write, execute/search by owner.
const OWNER_MASK = 0o700;
/// Read permission, owner.
const OWNER_READ = 0o400;
/// Write permission, owner.
const OWNER_WRITE = 0o200;
/// Execute/search permission, owner.
const OWNER_EXEC = 0o100;
/// Read, write, execute/search by group.
const GROUP_MASK = 0o70;
/// Read permission, group.
const GROUP_READ = 0o40;
/// Write permission, group.
const GROUP_WRITE = 0o20;
/// Execute/search permission, group.
const GROUP_EXEC = 0o10;
/// Read, write, execute/search by others.
const OTHER_MASK = 0o7;
/// Read permission, others.
const OTHER_READ = 0o4;
/// Write permission, others.
const OTHER_WRITE = 0o2;
/// Execute/search permission, others.
const OTHER_EXEC = 0o1;
}
}
impl StatMode {
fn from_type_mode(type_: FileType, mode: u16) -> Self {
let type_ = match type_ {
FileType::File => StatMode::FILE,
FileType::Dir => StatMode::DIR,
FileType::SymLink => StatMode::LINK,
FileType::CharDevice => StatMode::CHAR,
FileType::BlockDevice => StatMode::BLOCK,
FileType::Socket => StatMode::SOCKET,
FileType::NamedPipe => StatMode::FIFO,
_ => StatMode::NULL,
};
let mode = StatMode::from_bits_truncate(mode as u32);
type_ | mode
}
}
impl From<Metadata> for Stat {
fn from(info: Metadata) -> Self {
Stat {
dev: info.dev as u64,
ino: info.inode as u64,
mode: StatMode::from_type_mode(info.type_, info.mode as u16),
nlink: info.nlinks as u64,
uid: info.uid as u32,
gid: info.gid as u32,
rdev: 0,
size: info.size as u64,
blksize: info.blk_size as u64,
blocks: info.blocks as u64,
atime: info.atime,
mtime: info.mtime,
ctime: info.ctime,
_pad0: 0,
}
}
}
/// Write a Rust string to C string
pub unsafe fn write_cstr(ptr: *mut u8, s: &str) {
ptr.copy_from(s.as_ptr(), s.len());
ptr.add(s.len()).write(0);
}
pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result<isize> {
info!("fcntl: fd: {:?}, cmd: {:?}", &fd, cmd);
let current_ref = process::get_current();
let mut current = current_ref.lock().unwrap();
let file_table_ref = current.get_files();
let ret = fcntl::do_fcntl(file_table_ref, fd, cmd)?;
Ok(ret)
}
pub fn do_readlink(path: &str, buf: &mut [u8]) -> Result<usize> {
info!("readlink: path: {:?}", path);
let file_path = {
if path == "/proc/self/exe" {
let current_ref = process::get_current();
let current = current_ref.lock().unwrap();
current.get_elf_path().to_owned()
} else if path.starts_with("/proc/self/fd") {
let fd = path
.trim_start_matches("/proc/self/fd/")
.parse::<FileDesc>()
.map_err(|e| errno!(EBADF, "Invalid file descriptor"))?;
let current_ref = process::get_current();
let current = current_ref.lock().unwrap();
let file_ref = current.get_files().lock().unwrap().get(fd)?;
if let Ok(inode_file) = file_ref.as_inode_file() {
inode_file.get_abs_path().to_owned()
} else {
// TODO: support special device files
return_errno!(EINVAL, "not a normal file link")
}
} else {
// TODO: support symbolic links
return_errno!(EINVAL, "not a symbolic link")
}
};
let len = file_path.len().min(buf.len());
buf[0..len].copy_from_slice(&file_path.as_bytes()[0..len]);
Ok(len)
}

@ -154,3 +154,19 @@ impl File for PipeWriter {
unsafe impl Send for PipeWriter {} unsafe impl Send for PipeWriter {}
unsafe impl Sync for PipeWriter {} unsafe impl Sync for PipeWriter {}
pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2]> {
info!("pipe2: flags: {:#x}", flags);
let creation_flags = CreationFlags::from_bits_truncate(flags);
let current_ref = process::get_current();
let current = current_ref.lock().unwrap();
let pipe = Pipe::new(StatusFlags::from_bits_truncate(flags))?;
let file_table_ref = current.get_files();
let mut file_table = file_table_ref.lock().unwrap();
let close_on_spawn = creation_flags.must_close_on_spawn();
let reader_fd = file_table.put(Arc::new(Box::new(pipe.reader)), close_on_spawn);
let writer_fd = file_table.put(Arc::new(Box::new(pipe.writer)), close_on_spawn);
info!("pipe2: reader_fd: {}, writer_fd: {}", reader_fd, writer_fd);
Ok([reader_fd, writer_fd])
}

@ -1,10 +1,9 @@
use super::hostfs::HostFS; use super::hostfs::HostFS;
use super::sgx_impl::{SgxStorage, SgxUuidProvider}; use super::sefs::{SgxStorage, SgxUuidProvider};
use super::*; use super::*;
use config::{ConfigMount, ConfigMountFsType}; use config::{ConfigMount, ConfigMountFsType};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use rcore_fs::vfs::{FileSystem, FileType, FsError, INode};
use rcore_fs_mountfs::{MNode, MountFS}; use rcore_fs_mountfs::{MNode, MountFS};
use rcore_fs_ramfs::RamFS; use rcore_fs_ramfs::RamFS;
use rcore_fs_sefs::dev::*; use rcore_fs_sefs::dev::*;

@ -0,0 +1,7 @@
use super::sgx_aes_gcm_128bit_tag_t;
pub use self::sgx_storage::SgxStorage;
pub use self::sgx_uuid_provider::SgxUuidProvider;
mod sgx_storage;
mod sgx_uuid_provider;

@ -1,38 +1,13 @@
use super::sgx_aes_gcm_128bit_tag_t; use super::*;
use alloc::string::ToString; use rcore_fs_sefs::dev::{DevResult, DeviceError, File, SefsMac, Storage};
use rcore_fs::dev::TimeProvider;
use rcore_fs::vfs::Timespec;
use rcore_fs_sefs::dev::*;
use sgx_trts::libc;
use sgx_types::*;
use std::boxed::Box; use std::boxed::Box;
use std::collections::hash_map::DefaultHasher;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::hash::{Hash, Hasher};
use std::io::{Read, Seek, SeekFrom, Write}; use std::io::{Read, Seek, SeekFrom, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sgxfs::{remove, OpenOptions, SgxFile}; use std::sgxfs::{remove, OpenOptions, SgxFile};
use std::string::String;
use std::sync::{Arc, SgxMutex as Mutex}; use std::sync::{Arc, SgxMutex as Mutex};
use std::time::{SystemTime, UNIX_EPOCH};
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
extern "C" {
fn sgx_read_rand(rand_buf: *mut u8, buf_size: usize) -> sgx_status_t;
}
pub struct SgxUuidProvider;
impl UuidProvider for SgxUuidProvider {
fn generate_uuid(&self) -> SefsUuid {
let mut uuid: [u8; 16] = [0u8; 16];
let buf = uuid.as_mut_ptr();
let size = 16;
let status = unsafe { sgx_read_rand(buf, size) };
assert!(status == sgx_status_t::SGX_SUCCESS);
SefsUuid(uuid)
}
}
pub struct SgxStorage { pub struct SgxStorage {
path: PathBuf, path: PathBuf,

@ -0,0 +1,20 @@
use super::*;
use rcore_fs_sefs::dev::{SefsUuid, UuidProvider};
use sgx_types::sgx_status_t;
extern "C" {
fn sgx_read_rand(rand_buf: *mut u8, buf_size: usize) -> sgx_status_t;
}
pub struct SgxUuidProvider;
impl UuidProvider for SgxUuidProvider {
fn generate_uuid(&self) -> SefsUuid {
let mut uuid: [u8; 16] = [0u8; 16];
let buf = uuid.as_mut_ptr();
let size = 16;
let status = unsafe { sgx_read_rand(buf, size) };
assert!(status == sgx_status_t::SGX_SUCCESS);
SefsUuid(uuid)
}
}

190
src/libos/src/fs/stdio.rs Normal file

@ -0,0 +1,190 @@
use super::*;
pub struct StdoutFile {
inner: std::io::Stdout,
}
impl StdoutFile {
pub fn new() -> StdoutFile {
StdoutFile {
inner: std::io::stdout(),
}
}
}
impl File for StdoutFile {
fn write(&self, buf: &[u8]) -> Result<usize> {
let write_len = { self.inner.lock().write(buf).map_err(|e| errno!(e))? };
Ok(write_len)
}
fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize> {
self.write(buf)
}
fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
let mut guard = self.inner.lock();
let mut total_bytes = 0;
for buf in bufs {
match guard.write(buf) {
Ok(this_len) => {
total_bytes += this_len;
if this_len < buf.len() {
break;
}
}
Err(e) => {
match total_bytes {
// a complete failure
0 => return_errno!(EINVAL, "Failed to write"),
// a partially failure
_ => break,
}
}
}
}
Ok(total_bytes)
}
fn metadata(&self) -> Result<Metadata> {
Ok(Metadata {
dev: 0,
inode: 0,
size: 0,
blk_size: 0,
blocks: 0,
atime: Timespec { sec: 0, nsec: 0 },
mtime: Timespec { sec: 0, nsec: 0 },
ctime: Timespec { sec: 0, nsec: 0 },
type_: FileType::CharDevice,
mode: 0,
nlinks: 0,
uid: 0,
gid: 0,
rdev: 0,
})
}
fn sync_all(&self) -> Result<()> {
self.sync_data()
}
fn sync_data(&self) -> Result<()> {
self.inner.lock().flush()?;
Ok(())
}
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<()> {
let can_delegate_to_host = match cmd {
IoctlCmd::TIOCGWINSZ(_) => true,
IoctlCmd::TIOCSWINSZ(_) => true,
_ => false,
};
if !can_delegate_to_host {
return_errno!(EINVAL, "unknown ioctl cmd for stdout");
}
let cmd_bits = cmd.cmd_num() as c_int;
let cmd_arg_ptr = cmd.arg_ptr() as *const c_int;
let host_stdout_fd = {
use std::os::unix::io::AsRawFd;
self.inner.as_raw_fd() as i32
};
try_libc!(libc::ocall::ioctl_arg1(
host_stdout_fd,
cmd_bits,
cmd_arg_ptr
));
cmd.validate_arg_val()?;
Ok(())
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl Debug for StdoutFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "StdoutFile")
}
}
unsafe impl Send for StdoutFile {}
unsafe impl Sync for StdoutFile {}
pub struct StdinFile {
inner: std::io::Stdin,
}
impl StdinFile {
pub fn new() -> StdinFile {
StdinFile {
inner: std::io::stdin(),
}
}
}
impl File for StdinFile {
fn read(&self, buf: &mut [u8]) -> Result<usize> {
let read_len = { self.inner.lock().read(buf).map_err(|e| errno!(e))? };
Ok(read_len)
}
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
let mut guard = self.inner.lock();
let mut total_bytes = 0;
for buf in bufs {
match guard.read(buf) {
Ok(this_len) => {
total_bytes += this_len;
if this_len < buf.len() {
break;
}
}
Err(e) => {
match total_bytes {
// a complete failure
0 => return_errno!(EINVAL, "Failed to write"),
// a partially failure
_ => break,
}
}
}
}
Ok(total_bytes)
}
fn metadata(&self) -> Result<Metadata> {
Ok(Metadata {
dev: 0,
inode: 0,
size: 0,
blk_size: 0,
blocks: 0,
atime: Timespec { sec: 0, nsec: 0 },
mtime: Timespec { sec: 0, nsec: 0 },
ctime: Timespec { sec: 0, nsec: 0 },
type_: FileType::CharDevice,
mode: 0,
nlinks: 0,
uid: 0,
gid: 0,
rdev: 0,
})
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl Debug for StdinFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "StdinFile")
}
}
unsafe impl Send for StdinFile {}
unsafe impl Sync for StdinFile {}

@ -0,0 +1,364 @@
use super::file_ops;
use super::file_ops::{AccessibilityCheckFlags, AccessibilityCheckMode, FcntlCmd, AT_FDCWD};
use super::fs_ops;
use super::*;
use util::mem_util::from_user;
#[allow(non_camel_case_types)]
pub struct iovec_t {
base: *const c_void,
len: size_t,
}
pub fn do_open(path: *const i8, flags: u32, mode: u32) -> Result<isize> {
let path = from_user::clone_cstring_safely(path)?
.to_string_lossy()
.into_owned();
let fd = file_ops::do_open(&path, flags, mode)?;
Ok(fd as isize)
}
pub fn do_close(fd: FileDesc) -> Result<isize> {
file_ops::do_close(fd)?;
Ok(0)
}
pub fn do_read(fd: FileDesc, buf: *mut u8, size: usize) -> Result<isize> {
let safe_buf = {
from_user::check_mut_array(buf, size)?;
unsafe { std::slice::from_raw_parts_mut(buf, size) }
};
let len = file_ops::do_read(fd, safe_buf)?;
Ok(len as isize)
}
pub fn do_write(fd: FileDesc, buf: *const u8, size: usize) -> Result<isize> {
let safe_buf = {
from_user::check_array(buf, size)?;
unsafe { std::slice::from_raw_parts(buf, size) }
};
let len = file_ops::do_write(fd, safe_buf)?;
Ok(len as isize)
}
pub fn do_writev(fd: FileDesc, iov: *const iovec_t, count: i32) -> Result<isize> {
let count = {
if count < 0 {
return_errno!(EINVAL, "Invalid count of iovec");
}
count as usize
};
from_user::check_array(iov, count);
let bufs_vec = {
let mut bufs_vec = Vec::with_capacity(count);
for iov_i in 0..count {
let iov_ptr = unsafe { iov.offset(iov_i as isize) };
let iov = unsafe { &*iov_ptr };
let buf = unsafe { std::slice::from_raw_parts(iov.base as *const u8, iov.len) };
bufs_vec.push(buf);
}
bufs_vec
};
let bufs = &bufs_vec[..];
let len = file_ops::do_writev(fd, bufs)?;
Ok(len as isize)
}
pub fn do_readv(fd: FileDesc, iov: *mut iovec_t, count: i32) -> Result<isize> {
let count = {
if count < 0 {
return_errno!(EINVAL, "Invalid count of iovec");
}
count as usize
};
from_user::check_array(iov, count);
let mut bufs_vec = {
let mut bufs_vec = Vec::with_capacity(count);
for iov_i in 0..count {
let iov_ptr = unsafe { iov.offset(iov_i as isize) };
let iov = unsafe { &*iov_ptr };
let buf = unsafe { std::slice::from_raw_parts_mut(iov.base as *mut u8, iov.len) };
bufs_vec.push(buf);
}
bufs_vec
};
let bufs = &mut bufs_vec[..];
let len = file_ops::do_readv(fd, bufs)?;
Ok(len as isize)
}
pub fn do_pread(fd: FileDesc, buf: *mut u8, size: usize, offset: usize) -> Result<isize> {
let safe_buf = {
from_user::check_mut_array(buf, size)?;
unsafe { std::slice::from_raw_parts_mut(buf, size) }
};
let len = file_ops::do_pread(fd, safe_buf, offset)?;
Ok(len as isize)
}
pub fn do_pwrite(fd: FileDesc, buf: *const u8, size: usize, offset: usize) -> Result<isize> {
let safe_buf = {
from_user::check_array(buf, size)?;
unsafe { std::slice::from_raw_parts(buf, size) }
};
let len = file_ops::do_pwrite(fd, safe_buf, offset)?;
Ok(len as isize)
}
pub fn do_stat(path: *const i8, stat_buf: *mut Stat) -> Result<isize> {
let path = from_user::clone_cstring_safely(path)?
.to_string_lossy()
.into_owned();
from_user::check_mut_ptr(stat_buf)?;
let stat = file_ops::do_stat(&path)?;
unsafe {
stat_buf.write(stat);
}
Ok(0)
}
pub fn do_fstat(fd: FileDesc, stat_buf: *mut Stat) -> Result<isize> {
from_user::check_mut_ptr(stat_buf)?;
let stat = file_ops::do_fstat(fd)?;
unsafe {
stat_buf.write(stat);
}
Ok(0)
}
pub fn do_lstat(path: *const i8, stat_buf: *mut Stat) -> Result<isize> {
let path = from_user::clone_cstring_safely(path)?
.to_string_lossy()
.into_owned();
from_user::check_mut_ptr(stat_buf)?;
let stat = file_ops::do_lstat(&path)?;
unsafe {
stat_buf.write(stat);
}
Ok(0)
}
pub fn do_access(path: *const i8, mode: u32) -> Result<isize> {
let path = from_user::clone_cstring_safely(path)?
.to_string_lossy()
.into_owned();
let mode = AccessibilityCheckMode::from_u32(mode)?;
file_ops::do_access(&path, mode).map(|_| 0)
}
pub fn do_faccessat(dirfd: i32, path: *const i8, mode: u32, flags: u32) -> Result<isize> {
let dirfd = if dirfd >= 0 {
Some(dirfd as FileDesc)
} else if dirfd == AT_FDCWD {
None
} else {
return_errno!(EINVAL, "invalid dirfd");
};
let path = from_user::clone_cstring_safely(path)?
.to_string_lossy()
.into_owned();
let mode = AccessibilityCheckMode::from_u32(mode)?;
let flags = AccessibilityCheckFlags::from_u32(flags)?;
file_ops::do_faccessat(dirfd, &path, mode, flags).map(|_| 0)
}
pub fn do_lseek(fd: FileDesc, offset: off_t, whence: i32) -> Result<isize> {
let seek_from = match whence {
0 => {
// SEEK_SET
if offset < 0 {
return_errno!(EINVAL, "Invalid offset");
}
SeekFrom::Start(offset as u64)
}
1 => {
// SEEK_CUR
SeekFrom::Current(offset)
}
2 => {
// SEEK_END
SeekFrom::End(offset)
}
_ => {
return_errno!(EINVAL, "Invalid whence");
}
};
let offset = file_ops::do_lseek(fd, seek_from)?;
Ok(offset as isize)
}
pub fn do_fsync(fd: FileDesc) -> Result<isize> {
file_ops::do_fsync(fd)?;
Ok(0)
}
pub fn do_fdatasync(fd: FileDesc) -> Result<isize> {
file_ops::do_fdatasync(fd)?;
Ok(0)
}
pub fn do_truncate(path: *const i8, len: usize) -> Result<isize> {
let path = from_user::clone_cstring_safely(path)?
.to_string_lossy()
.into_owned();
file_ops::do_truncate(&path, len)?;
Ok(0)
}
pub fn do_ftruncate(fd: FileDesc, len: usize) -> Result<isize> {
file_ops::do_ftruncate(fd, len)?;
Ok(0)
}
pub fn do_getdents64(fd: FileDesc, buf: *mut u8, buf_size: usize) -> Result<isize> {
let safe_buf = {
from_user::check_mut_array(buf, buf_size)?;
unsafe { std::slice::from_raw_parts_mut(buf, buf_size) }
};
let len = file_ops::do_getdents64(fd, safe_buf)?;
Ok(len as isize)
}
pub fn do_sync() -> Result<isize> {
fs_ops::do_sync()?;
Ok(0)
}
pub fn do_pipe2(fds_u: *mut i32, flags: u32) -> Result<isize> {
from_user::check_mut_array(fds_u, 2)?;
// TODO: how to deal with open flags???
let fds = pipe::do_pipe2(flags as u32)?;
unsafe {
*fds_u.offset(0) = fds[0] as c_int;
*fds_u.offset(1) = fds[1] as c_int;
}
Ok(0)
}
pub fn do_dup(old_fd: FileDesc) -> Result<isize> {
let new_fd = file_ops::do_dup(old_fd)?;
Ok(new_fd as isize)
}
pub fn do_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result<isize> {
let new_fd = file_ops::do_dup2(old_fd, new_fd)?;
Ok(new_fd as isize)
}
pub fn do_dup3(old_fd: FileDesc, new_fd: FileDesc, flags: u32) -> Result<isize> {
let new_fd = file_ops::do_dup3(old_fd, new_fd, flags)?;
Ok(new_fd as isize)
}
pub fn do_chdir(path: *const i8) -> Result<isize> {
let path = from_user::clone_cstring_safely(path)?
.to_string_lossy()
.into_owned();
file_ops::do_chdir(&path)?;
Ok(0)
}
pub fn do_rename(oldpath: *const i8, newpath: *const i8) -> Result<isize> {
let oldpath = from_user::clone_cstring_safely(oldpath)?
.to_string_lossy()
.into_owned();
let newpath = from_user::clone_cstring_safely(newpath)?
.to_string_lossy()
.into_owned();
file_ops::do_rename(&oldpath, &newpath)?;
Ok(0)
}
pub fn do_mkdir(path: *const i8, mode: usize) -> Result<isize> {
let path = from_user::clone_cstring_safely(path)?
.to_string_lossy()
.into_owned();
file_ops::do_mkdir(&path, mode)?;
Ok(0)
}
pub fn do_rmdir(path: *const i8) -> Result<isize> {
let path = from_user::clone_cstring_safely(path)?
.to_string_lossy()
.into_owned();
file_ops::do_rmdir(&path)?;
Ok(0)
}
pub fn do_link(oldpath: *const i8, newpath: *const i8) -> Result<isize> {
let oldpath = from_user::clone_cstring_safely(oldpath)?
.to_string_lossy()
.into_owned();
let newpath = from_user::clone_cstring_safely(newpath)?
.to_string_lossy()
.into_owned();
file_ops::do_link(&oldpath, &newpath)?;
Ok(0)
}
pub fn do_unlink(path: *const i8) -> Result<isize> {
let path = from_user::clone_cstring_safely(path)?
.to_string_lossy()
.into_owned();
file_ops::do_unlink(&path)?;
Ok(0)
}
pub fn do_readlink(path: *const i8, buf: *mut u8, size: usize) -> Result<isize> {
let path = from_user::clone_cstring_safely(path)?
.to_string_lossy()
.into_owned();
let buf = {
from_user::check_array(buf, size)?;
unsafe { std::slice::from_raw_parts_mut(buf, size) }
};
let len = file_ops::do_readlink(&path, buf)?;
Ok(len as isize)
}
pub fn do_sendfile(
out_fd: FileDesc,
in_fd: FileDesc,
offset_ptr: *mut off_t,
count: usize,
) -> Result<isize> {
let offset = if offset_ptr.is_null() {
None
} else {
from_user::check_mut_ptr(offset_ptr)?;
Some(unsafe { offset_ptr.read() })
};
let (len, offset) = file_ops::do_sendfile(out_fd, in_fd, offset, count)?;
if !offset_ptr.is_null() {
unsafe {
offset_ptr.write(offset as off_t);
}
}
Ok(len as isize)
}
pub fn do_fcntl(fd: FileDesc, cmd: u32, arg: u64) -> Result<isize> {
let cmd = FcntlCmd::from_raw(cmd, arg)?;
file_ops::do_fcntl(fd, &cmd)
}
pub fn do_ioctl(fd: FileDesc, cmd: u32, argp: *mut u8) -> Result<isize> {
info!("ioctl: fd: {}, cmd: {}, argp: {:?}", fd, cmd, argp);
let mut ioctl_cmd = unsafe {
if argp.is_null() == false {
from_user::check_mut_ptr(argp)?;
}
IoctlCmd::new(cmd, argp)?
};
file_ops::do_ioctl(fd, &mut ioctl_cmd)?;
Ok(0)
}

@ -1,4 +1,5 @@
use super::*; use super::*;
use fs::{File, FileDesc, FileRef};
use std::any::Any; use std::any::Any;
use std::collections::btree_map::BTreeMap; use std::collections::btree_map::BTreeMap;
use std::fmt; use std::fmt;

@ -1,14 +1,17 @@
use super::*; use super::*;
use std::*; use std;
mod io_multiplexing;
mod iovs; mod iovs;
mod msg; mod msg;
mod msg_flags; mod msg_flags;
mod socket_file; mod socket_file;
mod syscalls; mod syscalls;
mod unix_socket;
pub use self::iovs::{Iovs, IovsMut, SliceAsLibcIovec}; pub use self::iovs::{Iovs, IovsMut, SliceAsLibcIovec};
pub use self::msg::{msghdr, msghdr_mut, MsgHdr, MsgHdrMut}; pub use self::msg::{msghdr, msghdr_mut, MsgHdr, MsgHdrMut};
pub use self::msg_flags::MsgFlags; pub use self::msg_flags::MsgFlags;
pub use self::socket_file::{AsSocket, SocketFile}; pub use self::socket_file::{AsSocket, SocketFile};
pub use self::syscalls::{do_recvmsg, do_sendmsg}; pub use self::syscalls::*;
pub use self::unix_socket::{AsUnixSocket, UnixSocketFile};

@ -1,6 +1,7 @@
use super::*; use super::*;
use fs::{AsUnixSocket, File, FileDesc, FileRef, UnixSocketFile}; use super::io_multiplexing;
use fs::{File, FileDesc, FileRef};
use process::Process; use process::Process;
use util::mem_util::from_user; use util::mem_util::from_user;
@ -124,3 +125,114 @@ impl c_msghdr_ext for msghdr_mut {
Ok(()) Ok(())
} }
} }
pub fn do_select(
nfds: c_int,
readfds: *mut libc::fd_set,
writefds: *mut libc::fd_set,
exceptfds: *mut libc::fd_set,
timeout: *const libc::timeval,
) -> Result<isize> {
// check arguments
if nfds < 0 || nfds >= libc::FD_SETSIZE as c_int {
return_errno!(EINVAL, "nfds is negative or exceeds the resource limit");
}
let nfds = nfds as usize;
let mut zero_fds0: libc::fd_set = unsafe { core::mem::zeroed() };
let mut zero_fds1: libc::fd_set = unsafe { core::mem::zeroed() };
let mut zero_fds2: libc::fd_set = unsafe { core::mem::zeroed() };
let readfds = if !readfds.is_null() {
from_user::check_mut_ptr(readfds)?;
unsafe { &mut *readfds }
} else {
&mut zero_fds0
};
let writefds = if !writefds.is_null() {
from_user::check_mut_ptr(writefds)?;
unsafe { &mut *writefds }
} else {
&mut zero_fds1
};
let exceptfds = if !exceptfds.is_null() {
from_user::check_mut_ptr(exceptfds)?;
unsafe { &mut *exceptfds }
} else {
&mut zero_fds2
};
let timeout = if !timeout.is_null() {
from_user::check_ptr(timeout)?;
Some(unsafe { timeout.read() })
} else {
None
};
let n = io_multiplexing::do_select(nfds, readfds, writefds, exceptfds, timeout)?;
Ok(n as isize)
}
pub fn do_poll(fds: *mut libc::pollfd, nfds: libc::nfds_t, timeout: c_int) -> Result<isize> {
from_user::check_mut_array(fds, nfds as usize)?;
let polls = unsafe { std::slice::from_raw_parts_mut(fds, nfds as usize) };
let n = io_multiplexing::do_poll(polls, timeout)?;
Ok(n as isize)
}
pub fn do_epoll_create(size: c_int) -> Result<isize> {
if size <= 0 {
return_errno!(EINVAL, "size is not positive");
}
do_epoll_create1(0)
}
pub fn do_epoll_create1(flags: c_int) -> Result<isize> {
let fd = io_multiplexing::do_epoll_create1(flags)?;
Ok(fd as isize)
}
pub fn do_epoll_ctl(
epfd: c_int,
op: c_int,
fd: c_int,
event: *const libc::epoll_event,
) -> Result<isize> {
if !event.is_null() {
from_user::check_ptr(event)?;
}
io_multiplexing::do_epoll_ctl(epfd as FileDesc, op, fd as FileDesc, event)?;
Ok(0)
}
pub fn do_epoll_wait(
epfd: c_int,
events: *mut libc::epoll_event,
maxevents: c_int,
timeout: c_int,
) -> Result<isize> {
let maxevents = {
if maxevents <= 0 {
return_errno!(EINVAL, "maxevents <= 0");
}
maxevents as usize
};
let events = {
from_user::check_mut_array(events, maxevents)?;
unsafe { std::slice::from_raw_parts_mut(events, maxevents) }
};
let count = io_multiplexing::do_epoll_wait(epfd as FileDesc, events, timeout)?;
Ok(count as isize)
}
pub fn do_epoll_pwait(
epfd: c_int,
events: *mut libc::epoll_event,
maxevents: c_int,
timeout: c_int,
sigmask: *const usize, //TODO:add sigset_t
) -> Result<isize> {
info!("epoll_pwait");
//TODO:add signal support
do_epoll_wait(epfd, events, maxevents, 0)
}

@ -1,5 +1,7 @@
use super::*; use super::*;
use alloc::string::ToString; use fs::{File, FileRef, IoctlCmd};
use rcore_fs::vfs::{FileType, Metadata, Timespec};
use std::any::Any;
use std::collections::btree_map::BTreeMap; use std::collections::btree_map::BTreeMap;
use std::fmt; use std::fmt;
use std::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering}; use std::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering};

@ -7,12 +7,9 @@
//! 3. Dispatch the syscall to `do_*` (at this file) //! 3. Dispatch the syscall to `do_*` (at this file)
//! 4. Do some memory checks then call `mod::do_*` (at each module) //! 4. Do some memory checks then call `mod::do_*` (at each module)
use fs::{ use fs::{File, FileDesc, FileRef, Stat};
AccessFlags, AccessModes, AsUnixSocket, FcntlCmd, File, FileDesc, FileRef, IoctlCmd,
UnixSocketFile, AT_FDCWD,
};
use misc::{resource_t, rlimit_t, utsname_t}; use misc::{resource_t, rlimit_t, utsname_t};
use net::{msghdr, msghdr_mut, AsSocket, SocketFile}; use net::{msghdr, msghdr_mut, AsSocket, AsUnixSocket, SocketFile, UnixSocketFile};
use process::{pid_t, ChildProcessFilter, CloneFlags, CpuSet, FileAction, FutexFlags, FutexOp}; use process::{pid_t, ChildProcessFilter, CloneFlags, CpuSet, FileAction, FutexFlags, FutexOp};
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::ptr; use std::ptr;
@ -72,81 +69,81 @@ pub extern "C" fn dispatch_syscall(
let ret = match num { let ret = match num {
// file // file
SYS_OPEN => do_open(arg0 as *const i8, arg1 as u32, arg2 as u32), SYS_OPEN => fs::do_open(arg0 as *const i8, arg1 as u32, arg2 as u32),
SYS_CLOSE => do_close(arg0 as FileDesc), SYS_CLOSE => fs::do_close(arg0 as FileDesc),
SYS_READ => do_read(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize), SYS_READ => fs::do_read(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize),
SYS_WRITE => do_write(arg0 as FileDesc, arg1 as *const u8, arg2 as usize), SYS_WRITE => fs::do_write(arg0 as FileDesc, arg1 as *const u8, arg2 as usize),
SYS_PREAD64 => do_pread( SYS_PREAD64 => fs::do_pread(
arg0 as FileDesc, arg0 as FileDesc,
arg1 as *mut u8, arg1 as *mut u8,
arg2 as usize, arg2 as usize,
arg3 as usize, arg3 as usize,
), ),
SYS_PWRITE64 => do_pwrite( SYS_PWRITE64 => fs::do_pwrite(
arg0 as FileDesc, arg0 as FileDesc,
arg1 as *const u8, arg1 as *const u8,
arg2 as usize, arg2 as usize,
arg3 as usize, arg3 as usize,
), ),
SYS_READV => do_readv(arg0 as FileDesc, arg1 as *mut iovec_t, arg2 as i32), SYS_READV => fs::do_readv(arg0 as FileDesc, arg1 as *mut fs::iovec_t, arg2 as i32),
SYS_WRITEV => do_writev(arg0 as FileDesc, arg1 as *mut iovec_t, arg2 as i32), SYS_WRITEV => fs::do_writev(arg0 as FileDesc, arg1 as *mut fs::iovec_t, arg2 as i32),
SYS_STAT => do_stat(arg0 as *const i8, arg1 as *mut fs::Stat), SYS_STAT => fs::do_stat(arg0 as *const i8, arg1 as *mut Stat),
SYS_FSTAT => do_fstat(arg0 as FileDesc, arg1 as *mut fs::Stat), SYS_FSTAT => fs::do_fstat(arg0 as FileDesc, arg1 as *mut Stat),
SYS_LSTAT => do_lstat(arg0 as *const i8, arg1 as *mut fs::Stat), SYS_LSTAT => fs::do_lstat(arg0 as *const i8, arg1 as *mut Stat),
SYS_ACCESS => do_access(arg0 as *const i8, arg1 as u32), SYS_ACCESS => fs::do_access(arg0 as *const i8, arg1 as u32),
SYS_FACCESSAT => do_faccessat(arg0 as i32, arg1 as *const i8, arg2 as u32, arg3 as u32), SYS_FACCESSAT => fs::do_faccessat(arg0 as i32, arg1 as *const i8, arg2 as u32, arg3 as u32),
SYS_LSEEK => do_lseek(arg0 as FileDesc, arg1 as off_t, arg2 as i32), SYS_LSEEK => fs::do_lseek(arg0 as FileDesc, arg1 as off_t, arg2 as i32),
SYS_FSYNC => do_fsync(arg0 as FileDesc), SYS_FSYNC => fs::do_fsync(arg0 as FileDesc),
SYS_FDATASYNC => do_fdatasync(arg0 as FileDesc), SYS_FDATASYNC => fs::do_fdatasync(arg0 as FileDesc),
SYS_TRUNCATE => do_truncate(arg0 as *const i8, arg1 as usize), SYS_TRUNCATE => fs::do_truncate(arg0 as *const i8, arg1 as usize),
SYS_FTRUNCATE => do_ftruncate(arg0 as FileDesc, arg1 as usize), SYS_FTRUNCATE => fs::do_ftruncate(arg0 as FileDesc, arg1 as usize),
SYS_GETDENTS64 => do_getdents64(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize), SYS_GETDENTS64 => fs::do_getdents64(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize),
SYS_SYNC => do_sync(), SYS_SYNC => fs::do_sync(),
SYS_GETCWD => do_getcwd(arg0 as *mut u8, arg1 as usize), SYS_GETCWD => do_getcwd(arg0 as *mut u8, arg1 as usize),
SYS_CHDIR => do_chdir(arg0 as *mut i8), SYS_CHDIR => fs::do_chdir(arg0 as *mut i8),
SYS_RENAME => do_rename(arg0 as *const i8, arg1 as *const i8), SYS_RENAME => fs::do_rename(arg0 as *const i8, arg1 as *const i8),
SYS_MKDIR => do_mkdir(arg0 as *const i8, arg1 as usize), SYS_MKDIR => fs::do_mkdir(arg0 as *const i8, arg1 as usize),
SYS_RMDIR => do_rmdir(arg0 as *const i8), SYS_RMDIR => fs::do_rmdir(arg0 as *const i8),
SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8), SYS_LINK => fs::do_link(arg0 as *const i8, arg1 as *const i8),
SYS_UNLINK => do_unlink(arg0 as *const i8), SYS_UNLINK => fs::do_unlink(arg0 as *const i8),
SYS_READLINK => do_readlink(arg0 as *const i8, arg1 as *mut u8, arg2 as usize), SYS_READLINK => fs::do_readlink(arg0 as *const i8, arg1 as *mut u8, arg2 as usize),
SYS_SENDFILE => do_sendfile( SYS_SENDFILE => fs::do_sendfile(
arg0 as FileDesc, arg0 as FileDesc,
arg1 as FileDesc, arg1 as FileDesc,
arg2 as *mut off_t, arg2 as *mut off_t,
arg3 as usize, arg3 as usize,
), ),
SYS_FCNTL => do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64), SYS_FCNTL => fs::do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64),
SYS_IOCTL => do_ioctl(arg0 as FileDesc, arg1 as u32, arg2 as *mut u8), SYS_IOCTL => fs::do_ioctl(arg0 as FileDesc, arg1 as u32, arg2 as *mut u8),
// IO multiplexing // IO multiplexing
SYS_SELECT => do_select( SYS_SELECT => net::do_select(
arg0 as c_int, arg0 as c_int,
arg1 as *mut libc::fd_set, arg1 as *mut libc::fd_set,
arg2 as *mut libc::fd_set, arg2 as *mut libc::fd_set,
arg3 as *mut libc::fd_set, arg3 as *mut libc::fd_set,
arg4 as *const libc::timeval, arg4 as *const libc::timeval,
), ),
SYS_POLL => do_poll( SYS_POLL => net::do_poll(
arg0 as *mut libc::pollfd, arg0 as *mut libc::pollfd,
arg1 as libc::nfds_t, arg1 as libc::nfds_t,
arg2 as c_int, arg2 as c_int,
), ),
SYS_EPOLL_CREATE => do_epoll_create(arg0 as c_int), SYS_EPOLL_CREATE => net::do_epoll_create(arg0 as c_int),
SYS_EPOLL_CREATE1 => do_epoll_create1(arg0 as c_int), SYS_EPOLL_CREATE1 => net::do_epoll_create1(arg0 as c_int),
SYS_EPOLL_CTL => do_epoll_ctl( SYS_EPOLL_CTL => net::do_epoll_ctl(
arg0 as c_int, arg0 as c_int,
arg1 as c_int, arg1 as c_int,
arg2 as c_int, arg2 as c_int,
arg3 as *const libc::epoll_event, arg3 as *const libc::epoll_event,
), ),
SYS_EPOLL_WAIT => do_epoll_wait( SYS_EPOLL_WAIT => net::do_epoll_wait(
arg0 as c_int, arg0 as c_int,
arg1 as *mut libc::epoll_event, arg1 as *mut libc::epoll_event,
arg2 as c_int, arg2 as c_int,
arg3 as c_int, arg3 as c_int,
), ),
SYS_EPOLL_PWAIT => do_epoll_pwait( SYS_EPOLL_PWAIT => net::do_epoll_pwait(
arg0 as c_int, arg0 as c_int,
arg1 as *mut libc::epoll_event, arg1 as *mut libc::epoll_event,
arg2 as c_int, arg2 as c_int,
@ -225,11 +222,11 @@ pub extern "C" fn dispatch_syscall(
SYS_MPROTECT => do_mprotect(arg0 as usize, arg1 as usize, arg2 as u32), SYS_MPROTECT => do_mprotect(arg0 as usize, arg1 as usize, arg2 as u32),
SYS_BRK => do_brk(arg0 as usize), SYS_BRK => do_brk(arg0 as usize),
SYS_PIPE => do_pipe2(arg0 as *mut i32, 0), SYS_PIPE => fs::do_pipe2(arg0 as *mut i32, 0),
SYS_PIPE2 => do_pipe2(arg0 as *mut i32, arg1 as u32), SYS_PIPE2 => fs::do_pipe2(arg0 as *mut i32, arg1 as u32),
SYS_DUP => do_dup(arg0 as FileDesc), SYS_DUP => fs::do_dup(arg0 as FileDesc),
SYS_DUP2 => do_dup2(arg0 as FileDesc, arg1 as FileDesc), SYS_DUP2 => fs::do_dup2(arg0 as FileDesc, arg1 as FileDesc),
SYS_DUP3 => do_dup3(arg0 as FileDesc, arg1 as FileDesc, arg2 as u32), SYS_DUP3 => fs::do_dup3(arg0 as FileDesc, arg1 as FileDesc, arg2 as u32),
SYS_GETTIMEOFDAY => do_gettimeofday(arg0 as *mut timeval_t), SYS_GETTIMEOFDAY => do_gettimeofday(arg0 as *mut timeval_t),
SYS_CLOCK_GETTIME => do_clock_gettime(arg0 as clockid_t, arg1 as *mut timespec_t), SYS_CLOCK_GETTIME => do_clock_gettime(arg0 as clockid_t, arg1 as *mut timespec_t),
@ -362,12 +359,6 @@ fn print_syscall_timing() {
} }
} }
#[allow(non_camel_case_types)]
pub struct iovec_t {
base: *const c_void,
len: size_t,
}
/* /*
* This Rust-version of fdop correspond to the C-version one in Occlum. * This Rust-version of fdop correspond to the C-version one in Occlum.
* See <path_to_musl_libc>/src/process/fdop.h. * See <path_to_musl_libc>/src/process/fdop.h.
@ -518,196 +509,6 @@ pub fn do_futex(
} }
} }
fn do_open(path: *const i8, flags: u32, mode: u32) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
let fd = fs::do_open(&path, flags, mode)?;
Ok(fd as isize)
}
fn do_close(fd: FileDesc) -> Result<isize> {
fs::do_close(fd)?;
Ok(0)
}
fn do_read(fd: FileDesc, buf: *mut u8, size: usize) -> Result<isize> {
let safe_buf = {
check_mut_array(buf, size)?;
unsafe { std::slice::from_raw_parts_mut(buf, size) }
};
let len = fs::do_read(fd, safe_buf)?;
Ok(len as isize)
}
fn do_write(fd: FileDesc, buf: *const u8, size: usize) -> Result<isize> {
let safe_buf = {
check_array(buf, size)?;
unsafe { std::slice::from_raw_parts(buf, size) }
};
let len = fs::do_write(fd, safe_buf)?;
Ok(len as isize)
}
fn do_writev(fd: FileDesc, iov: *const iovec_t, count: i32) -> Result<isize> {
let count = {
if count < 0 {
return_errno!(EINVAL, "Invalid count of iovec");
}
count as usize
};
check_array(iov, count);
let bufs_vec = {
let mut bufs_vec = Vec::with_capacity(count);
for iov_i in 0..count {
let iov_ptr = unsafe { iov.offset(iov_i as isize) };
let iov = unsafe { &*iov_ptr };
let buf = unsafe { std::slice::from_raw_parts(iov.base as *const u8, iov.len) };
bufs_vec.push(buf);
}
bufs_vec
};
let bufs = &bufs_vec[..];
let len = fs::do_writev(fd, bufs)?;
Ok(len as isize)
}
fn do_readv(fd: FileDesc, iov: *mut iovec_t, count: i32) -> Result<isize> {
let count = {
if count < 0 {
return_errno!(EINVAL, "Invalid count of iovec");
}
count as usize
};
check_array(iov, count);
let mut bufs_vec = {
let mut bufs_vec = Vec::with_capacity(count);
for iov_i in 0..count {
let iov_ptr = unsafe { iov.offset(iov_i as isize) };
let iov = unsafe { &*iov_ptr };
let buf = unsafe { std::slice::from_raw_parts_mut(iov.base as *mut u8, iov.len) };
bufs_vec.push(buf);
}
bufs_vec
};
let bufs = &mut bufs_vec[..];
let len = fs::do_readv(fd, bufs)?;
Ok(len as isize)
}
fn do_pread(fd: FileDesc, buf: *mut u8, size: usize, offset: usize) -> Result<isize> {
let safe_buf = {
check_mut_array(buf, size)?;
unsafe { std::slice::from_raw_parts_mut(buf, size) }
};
let len = fs::do_pread(fd, safe_buf, offset)?;
Ok(len as isize)
}
fn do_pwrite(fd: FileDesc, buf: *const u8, size: usize, offset: usize) -> Result<isize> {
let safe_buf = {
check_array(buf, size)?;
unsafe { std::slice::from_raw_parts(buf, size) }
};
let len = fs::do_pwrite(fd, safe_buf, offset)?;
Ok(len as isize)
}
fn do_stat(path: *const i8, stat_buf: *mut fs::Stat) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
check_mut_ptr(stat_buf)?;
let stat = fs::do_stat(&path)?;
unsafe {
stat_buf.write(stat);
}
Ok(0)
}
fn do_fstat(fd: FileDesc, stat_buf: *mut fs::Stat) -> Result<isize> {
check_mut_ptr(stat_buf)?;
let stat = fs::do_fstat(fd)?;
unsafe {
stat_buf.write(stat);
}
Ok(0)
}
fn do_lstat(path: *const i8, stat_buf: *mut fs::Stat) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
check_mut_ptr(stat_buf)?;
let stat = fs::do_lstat(&path)?;
unsafe {
stat_buf.write(stat);
}
Ok(0)
}
fn do_lseek(fd: FileDesc, offset: off_t, whence: i32) -> Result<isize> {
let seek_from = match whence {
0 => {
// SEEK_SET
if offset < 0 {
return_errno!(EINVAL, "Invalid offset");
}
SeekFrom::Start(offset as u64)
}
1 => {
// SEEK_CUR
SeekFrom::Current(offset)
}
2 => {
// SEEK_END
SeekFrom::End(offset)
}
_ => {
return_errno!(EINVAL, "Invalid whence");
}
};
let offset = fs::do_lseek(fd, seek_from)?;
Ok(offset as isize)
}
fn do_fsync(fd: FileDesc) -> Result<isize> {
fs::do_fsync(fd)?;
Ok(0)
}
fn do_fdatasync(fd: FileDesc) -> Result<isize> {
fs::do_fdatasync(fd)?;
Ok(0)
}
fn do_truncate(path: *const i8, len: usize) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
fs::do_truncate(&path, len)?;
Ok(0)
}
fn do_ftruncate(fd: FileDesc, len: usize) -> Result<isize> {
fs::do_ftruncate(fd, len)?;
Ok(0)
}
fn do_getdents64(fd: FileDesc, buf: *mut u8, buf_size: usize) -> Result<isize> {
let safe_buf = {
check_mut_array(buf, buf_size)?;
unsafe { std::slice::from_raw_parts_mut(buf, buf_size) }
};
let len = fs::do_getdents64(fd, safe_buf)?;
Ok(len as isize)
}
fn do_sync() -> Result<isize> {
fs::do_sync()?;
Ok(0)
}
fn do_mmap( fn do_mmap(
addr: usize, addr: usize,
size: usize, size: usize,
@ -817,32 +618,6 @@ fn do_getegid() -> Result<isize> {
Ok(0) Ok(0)
} }
fn do_pipe2(fds_u: *mut i32, flags: u32) -> Result<isize> {
check_mut_array(fds_u, 2)?;
// TODO: how to deal with open flags???
let fds = fs::do_pipe2(flags as u32)?;
unsafe {
*fds_u.offset(0) = fds[0] as c_int;
*fds_u.offset(1) = fds[1] as c_int;
}
Ok(0)
}
fn do_dup(old_fd: FileDesc) -> Result<isize> {
let new_fd = fs::do_dup(old_fd)?;
Ok(new_fd as isize)
}
fn do_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result<isize> {
let new_fd = fs::do_dup2(old_fd, new_fd)?;
Ok(new_fd as isize)
}
fn do_dup3(old_fd: FileDesc, new_fd: FileDesc, flags: u32) -> Result<isize> {
let new_fd = fs::do_dup3(old_fd, new_fd, flags)?;
Ok(new_fd as isize)
}
// TODO: handle tz: timezone_t // TODO: handle tz: timezone_t
fn do_gettimeofday(tv_u: *mut timeval_t) -> Result<isize> { fn do_gettimeofday(tv_u: *mut timeval_t) -> Result<isize> {
check_mut_ptr(tv_u)?; check_mut_ptr(tv_u)?;
@ -921,101 +696,6 @@ fn do_getcwd(buf: *mut u8, size: usize) -> Result<isize> {
Ok(buf as isize) Ok(buf as isize)
} }
fn do_chdir(path: *const i8) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
fs::do_chdir(&path)?;
Ok(0)
}
fn do_rename(oldpath: *const i8, newpath: *const i8) -> Result<isize> {
let oldpath = clone_cstring_safely(oldpath)?
.to_string_lossy()
.into_owned();
let newpath = clone_cstring_safely(newpath)?
.to_string_lossy()
.into_owned();
fs::do_rename(&oldpath, &newpath)?;
Ok(0)
}
fn do_mkdir(path: *const i8, mode: usize) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
fs::do_mkdir(&path, mode)?;
Ok(0)
}
fn do_rmdir(path: *const i8) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
fs::do_rmdir(&path)?;
Ok(0)
}
fn do_link(oldpath: *const i8, newpath: *const i8) -> Result<isize> {
let oldpath = clone_cstring_safely(oldpath)?
.to_string_lossy()
.into_owned();
let newpath = clone_cstring_safely(newpath)?
.to_string_lossy()
.into_owned();
fs::do_link(&oldpath, &newpath)?;
Ok(0)
}
fn do_unlink(path: *const i8) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
fs::do_unlink(&path)?;
Ok(0)
}
fn do_readlink(path: *const i8, buf: *mut u8, size: usize) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
let buf = {
check_array(buf, size)?;
unsafe { std::slice::from_raw_parts_mut(buf, size) }
};
let len = fs::do_readlink(&path, buf)?;
Ok(len as isize)
}
fn do_sendfile(
out_fd: FileDesc,
in_fd: FileDesc,
offset_ptr: *mut off_t,
count: usize,
) -> Result<isize> {
let offset = if offset_ptr.is_null() {
None
} else {
check_mut_ptr(offset_ptr)?;
Some(unsafe { offset_ptr.read() })
};
let (len, offset) = fs::do_sendfile(out_fd, in_fd, offset, count)?;
if !offset_ptr.is_null() {
unsafe {
offset_ptr.write(offset as off_t);
}
}
Ok(len as isize)
}
fn do_fcntl(fd: FileDesc, cmd: u32, arg: u64) -> Result<isize> {
let cmd = FcntlCmd::from_raw(cmd, arg)?;
fs::do_fcntl(fd, &cmd)
}
fn do_ioctl(fd: FileDesc, cmd: u32, argp: *mut u8) -> Result<isize> {
info!("ioctl: fd: {}, cmd: {}, argp: {:?}", fd, cmd, argp);
let mut ioctl_cmd = unsafe {
if argp.is_null() == false {
check_mut_ptr(argp)?;
}
IoctlCmd::new(cmd, argp)?
};
fs::do_ioctl(fd, &mut ioctl_cmd)?;
Ok(0)
}
fn do_arch_prctl(code: u32, addr: *mut usize) -> Result<isize> { fn do_arch_prctl(code: u32, addr: *mut usize) -> Result<isize> {
let code = process::ArchPrctlCode::from_u32(code)?; let code = process::ArchPrctlCode::from_u32(code)?;
check_mut_ptr(addr)?; check_mut_ptr(addr)?;
@ -1406,117 +1086,6 @@ fn do_socketpair(
} }
} }
fn do_select(
nfds: c_int,
readfds: *mut libc::fd_set,
writefds: *mut libc::fd_set,
exceptfds: *mut libc::fd_set,
timeout: *const libc::timeval,
) -> Result<isize> {
// check arguments
if nfds < 0 || nfds >= libc::FD_SETSIZE as c_int {
return_errno!(EINVAL, "nfds is negative or exceeds the resource limit");
}
let nfds = nfds as usize;
let mut zero_fds0: libc::fd_set = unsafe { core::mem::zeroed() };
let mut zero_fds1: libc::fd_set = unsafe { core::mem::zeroed() };
let mut zero_fds2: libc::fd_set = unsafe { core::mem::zeroed() };
let readfds = if !readfds.is_null() {
check_mut_ptr(readfds)?;
unsafe { &mut *readfds }
} else {
&mut zero_fds0
};
let writefds = if !writefds.is_null() {
check_mut_ptr(writefds)?;
unsafe { &mut *writefds }
} else {
&mut zero_fds1
};
let exceptfds = if !exceptfds.is_null() {
check_mut_ptr(exceptfds)?;
unsafe { &mut *exceptfds }
} else {
&mut zero_fds2
};
let timeout = if !timeout.is_null() {
check_ptr(timeout)?;
Some(unsafe { timeout.read() })
} else {
None
};
let n = fs::do_select(nfds, readfds, writefds, exceptfds, timeout)?;
Ok(n as isize)
}
fn do_poll(fds: *mut libc::pollfd, nfds: libc::nfds_t, timeout: c_int) -> Result<isize> {
check_mut_array(fds, nfds as usize)?;
let polls = unsafe { std::slice::from_raw_parts_mut(fds, nfds as usize) };
let n = fs::do_poll(polls, timeout)?;
Ok(n as isize)
}
fn do_epoll_create(size: c_int) -> Result<isize> {
if size <= 0 {
return_errno!(EINVAL, "size is not positive");
}
do_epoll_create1(0)
}
fn do_epoll_create1(flags: c_int) -> Result<isize> {
let fd = fs::do_epoll_create1(flags)?;
Ok(fd as isize)
}
fn do_epoll_ctl(
epfd: c_int,
op: c_int,
fd: c_int,
event: *const libc::epoll_event,
) -> Result<isize> {
if !event.is_null() {
check_ptr(event)?;
}
fs::do_epoll_ctl(epfd as FileDesc, op, fd as FileDesc, event)?;
Ok(0)
}
fn do_epoll_wait(
epfd: c_int,
events: *mut libc::epoll_event,
maxevents: c_int,
timeout: c_int,
) -> Result<isize> {
let maxevents = {
if maxevents <= 0 {
return_errno!(EINVAL, "maxevents <= 0");
}
maxevents as usize
};
let events = {
check_mut_array(events, maxevents)?;
unsafe { std::slice::from_raw_parts_mut(events, maxevents) }
};
let count = fs::do_epoll_wait(epfd as FileDesc, events, timeout)?;
Ok(count as isize)
}
fn do_epoll_pwait(
epfd: c_int,
events: *mut libc::epoll_event,
maxevents: c_int,
timeout: c_int,
sigmask: *const usize, //TODO:add sigset_t
) -> Result<isize> {
info!("epoll_pwait");
//TODO:add signal support
do_epoll_wait(epfd, events, maxevents, 0)
}
fn do_uname(name: *mut utsname_t) -> Result<isize> { fn do_uname(name: *mut utsname_t) -> Result<isize> {
check_mut_ptr(name)?; check_mut_ptr(name)?;
let name = unsafe { &mut *name }; let name = unsafe { &mut *name };
@ -1549,26 +1118,6 @@ fn do_prlimit(
misc::do_prlimit(pid, resource, new_limit, old_limit).map(|_| 0) misc::do_prlimit(pid, resource, new_limit, old_limit).map(|_| 0)
} }
fn do_access(path: *const i8, mode: u32) -> Result<isize> {
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
let mode = AccessModes::from_u32(mode)?;
fs::do_access(&path, mode).map(|_| 0)
}
fn do_faccessat(dirfd: i32, path: *const i8, mode: u32, flags: u32) -> Result<isize> {
let dirfd = if dirfd >= 0 {
Some(dirfd as FileDesc)
} else if dirfd == AT_FDCWD {
None
} else {
return_errno!(EINVAL, "invalid dirfd");
};
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
let mode = AccessModes::from_u32(mode)?;
let flags = AccessFlags::from_u32(flags)?;
fs::do_faccessat(dirfd, &path, mode, flags).map(|_| 0)
}
// TODO: implement signals // TODO: implement signals
fn do_rt_sigaction() -> Result<isize> { fn do_rt_sigaction() -> Result<isize> {