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:
parent
cfa6532768
commit
de904bf628
11
src/libos/src/fs/dev_fs/mod.rs
Normal file
11
src/libos/src/fs/dev_fs/mod.rs
Normal file
@ -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 std;
|
||||
use std::borrow::BorrowMut;
|
||||
use std::fmt;
|
||||
use std::io::SeekFrom;
|
||||
|
||||
macro_rules! return_op_unsupported_error {
|
||||
($op_name: expr, $errno: expr) => {{
|
||||
@ -88,436 +84,6 @@ pub trait File: Debug + Sync + Send + Any {
|
||||
|
||||
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)]
|
||||
struct FileOpNotSupportedError {
|
||||
errno: Errno,
|
||||
|
@ -1,32 +1,29 @@
|
||||
use super::*;
|
||||
|
||||
//int faccessat(int dirfd, const char *pathname, int mode, int flags);
|
||||
//int access(const char *pathname, int mode);
|
||||
|
||||
bitflags! {
|
||||
pub struct AccessModes : u32 {
|
||||
pub struct AccessibilityCheckMode : u32 {
|
||||
const X_OK = 1;
|
||||
const W_OK = 2;
|
||||
const R_OK = 4;
|
||||
}
|
||||
}
|
||||
|
||||
impl AccessModes {
|
||||
pub fn from_u32(bits: u32) -> Result<AccessModes> {
|
||||
AccessModes::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid mode"))
|
||||
impl AccessibilityCheckMode {
|
||||
pub fn from_u32(bits: u32) -> Result<AccessibilityCheckMode> {
|
||||
AccessibilityCheckMode::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid mode"))
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct AccessFlags : u32 {
|
||||
pub struct AccessibilityCheckFlags : u32 {
|
||||
const AT_SYMLINK_NOFOLLOW = 0x100;
|
||||
const AT_EACCESS = 0x200;
|
||||
}
|
||||
}
|
||||
|
||||
impl AccessFlags {
|
||||
pub fn from_u32(bits: u32) -> Result<AccessFlags> {
|
||||
AccessFlags::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid flags"))
|
||||
impl AccessibilityCheckFlags {
|
||||
pub fn from_u32(bits: u32) -> Result<AccessibilityCheckFlags> {
|
||||
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(
|
||||
dirfd: Option<FileDesc>,
|
||||
path: &str,
|
||||
mode: AccessModes,
|
||||
flags: AccessFlags,
|
||||
mode: AccessibilityCheckMode,
|
||||
flags: AccessibilityCheckFlags,
|
||||
) -> Result<()> {
|
||||
info!(
|
||||
"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);
|
||||
let current_ref = process::get_current();
|
||||
let mut current = current_ref.lock().unwrap();
|
15
src/libos/src/fs/file_ops/chdir.rs
Normal file
15
src/libos/src/fs/file_ops/chdir.rs
Normal file
@ -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(())
|
||||
}
|
11
src/libos/src/fs/file_ops/close.rs
Normal file
11
src/libos/src/fs/file_ops/close.rs
Normal file
@ -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(())
|
||||
}
|
100
src/libos/src/fs/file_ops/dirent.rs
Normal file
100
src/libos/src/fs/file_ops/dirent.rs
Normal file
@ -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)
|
||||
}
|
37
src/libos/src/fs/file_ops/dup.rs
Normal file
37
src/libos/src/fs/file_ops/dup.rs
Normal file
@ -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 process::FileTableRef;
|
||||
|
||||
#[derive(Debug)]
|
||||
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 ret = match cmd {
|
||||
FcntlCmd::DupFd(min_fd) => {
|
19
src/libos/src/fs/file_ops/fsync.rs
Normal file
19
src/libos/src/fs/file_ops/fsync.rs
Normal file
@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
13
src/libos/src/fs/file_ops/link.rs
Normal file
13
src/libos/src/fs/file_ops/link.rs
Normal file
@ -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(())
|
||||
}
|
8
src/libos/src/fs/file_ops/lseek.rs
Normal file
8
src/libos/src/fs/file_ops/lseek.rs
Normal file
@ -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)
|
||||
}
|
19
src/libos/src/fs/file_ops/mkdir.rs
Normal file
19
src/libos/src/fs/file_ops/mkdir.rs
Normal file
@ -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(())
|
||||
}
|
141
src/libos/src/fs/file_ops/mod.rs
Normal file
141
src/libos/src/fs/file_ops/mod.rs
Normal file
@ -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)
|
||||
}
|
23
src/libos/src/fs/file_ops/open.rs
Normal file
23
src/libos/src/fs/file_ops/open.rs
Normal file
@ -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)
|
||||
}
|
25
src/libos/src/fs/file_ops/read.rs
Normal file
25
src/libos/src/fs/file_ops/read.rs
Normal file
@ -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)
|
||||
}
|
15
src/libos/src/fs/file_ops/rename.rs
Normal file
15
src/libos/src/fs/file_ops/rename.rs
Normal file
@ -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(())
|
||||
}
|
16
src/libos/src/fs/file_ops/rmdir.rs
Normal file
16
src/libos/src/fs/file_ops/rmdir.rs
Normal file
@ -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(())
|
||||
}
|
52
src/libos/src/fs/file_ops/sendfile.rs
Normal file
52
src/libos/src/fs/file_ops/sendfile.rs
Normal file
@ -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))
|
||||
}
|
151
src/libos/src/fs/file_ops/stat.rs
Normal file
151
src/libos/src/fs/file_ops/stat.rs
Normal file
@ -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)
|
||||
}
|
32
src/libos/src/fs/file_ops/symlink.rs
Normal file
32
src/libos/src/fs/file_ops/symlink.rs
Normal file
@ -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)
|
||||
}
|
18
src/libos/src/fs/file_ops/truncate.rs
Normal file
18
src/libos/src/fs/file_ops/truncate.rs
Normal file
@ -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(())
|
||||
}
|
16
src/libos/src/fs/file_ops/unlink.rs
Normal file
16
src/libos/src/fs/file_ops/unlink.rs
Normal file
@ -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(())
|
||||
}
|
25
src/libos/src/fs/file_ops/write.rs
Normal file
25
src/libos/src/fs/file_ops/write.rs
Normal file
@ -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 std;
|
||||
|
||||
pub type FileDesc = u32;
|
||||
|
||||
|
5
src/libos/src/fs/fs_ops/mod.rs
Normal file
5
src/libos/src/fs/fs_ops/mod.rs
Normal file
@ -0,0 +1,5 @@
|
||||
use super::*;
|
||||
|
||||
pub use self::sync::do_sync;
|
||||
|
||||
mod sync;
|
7
src/libos/src/fs/fs_ops/sync.rs
Normal file
7
src/libos/src/fs/fs_ops/sync.rs
Normal file
@ -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 rcore_fs_sefs::dev::SefsMac;
|
||||
use sgx_trts::libc::S_IRUSR;
|
||||
use std::fmt;
|
||||
use sgx_trts::libc::{S_IRUSR, S_IWUSR};
|
||||
|
||||
pub struct INodeFile {
|
||||
inode: Arc<dyn INode>,
|
||||
|
@ -1,756 +1,32 @@
|
||||
use super::*;
|
||||
|
||||
use net::{AsSocket, SocketFile};
|
||||
use process::Process;
|
||||
use rcore_fs::vfs::{FileType, FsError, INode, Metadata, Timespec};
|
||||
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 process;
|
||||
use rcore_fs::vfs::{FileSystem, FileType, FsError, INode, Metadata, Timespec};
|
||||
use std;
|
||||
use std::any::Any;
|
||||
use std::fmt;
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
mod access;
|
||||
mod dev_null;
|
||||
mod dev_random;
|
||||
mod dev_sgx;
|
||||
mod dev_zero;
|
||||
mod fcntl;
|
||||
pub use self::file::{File, FileRef};
|
||||
pub use self::file_ops::{AccessMode, CreationFlags, Stat, StatusFlags};
|
||||
pub use self::file_ops::{IoctlCmd, StructuredIoctlArgType, StructuredIoctlNum};
|
||||
pub use self::file_table::{FileDesc, FileTable};
|
||||
pub use self::inode_file::{AsINodeFile, INodeExt, INodeFile};
|
||||
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_flags;
|
||||
mod file_ops;
|
||||
mod file_table;
|
||||
mod fs_ops;
|
||||
mod hostfs;
|
||||
mod inode_file;
|
||||
mod io_multiplexing;
|
||||
mod ioctl;
|
||||
mod pipe;
|
||||
mod root_inode;
|
||||
mod sgx_impl;
|
||||
mod unix_socket;
|
||||
|
||||
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)
|
||||
}
|
||||
mod rootfs;
|
||||
mod sefs;
|
||||
mod stdio;
|
||||
mod syscalls;
|
||||
|
@ -154,3 +154,19 @@ impl File for PipeWriter {
|
||||
|
||||
unsafe impl Send 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::sgx_impl::{SgxStorage, SgxUuidProvider};
|
||||
use super::sefs::{SgxStorage, SgxUuidProvider};
|
||||
use super::*;
|
||||
use config::{ConfigMount, ConfigMountFsType};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use rcore_fs::vfs::{FileSystem, FileType, FsError, INode};
|
||||
use rcore_fs_mountfs::{MNode, MountFS};
|
||||
use rcore_fs_ramfs::RamFS;
|
||||
use rcore_fs_sefs::dev::*;
|
7
src/libos/src/fs/sefs/mod.rs
Normal file
7
src/libos/src/fs/sefs/mod.rs
Normal file
@ -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 alloc::string::ToString;
|
||||
use rcore_fs::dev::TimeProvider;
|
||||
use rcore_fs::vfs::Timespec;
|
||||
use rcore_fs_sefs::dev::*;
|
||||
use sgx_trts::libc;
|
||||
use sgx_types::*;
|
||||
use super::*;
|
||||
use rcore_fs_sefs::dev::{DevResult, DeviceError, File, SefsMac, Storage};
|
||||
use std::boxed::Box;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::collections::BTreeMap;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::io::{Read, Seek, SeekFrom, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sgxfs::{remove, OpenOptions, SgxFile};
|
||||
use std::string::String;
|
||||
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 {
|
||||
path: PathBuf,
|
20
src/libos/src/fs/sefs/sgx_uuid_provider.rs
Normal file
20
src/libos/src/fs/sefs/sgx_uuid_provider.rs
Normal file
@ -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
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 {}
|
364
src/libos/src/fs/syscalls.rs
Normal file
364
src/libos/src/fs/syscalls.rs
Normal file
@ -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 fs::{File, FileDesc, FileRef};
|
||||
use std::any::Any;
|
||||
use std::collections::btree_map::BTreeMap;
|
||||
use std::fmt;
|
@ -1,14 +1,17 @@
|
||||
use super::*;
|
||||
use std::*;
|
||||
use std;
|
||||
|
||||
mod io_multiplexing;
|
||||
mod iovs;
|
||||
mod msg;
|
||||
mod msg_flags;
|
||||
mod socket_file;
|
||||
mod syscalls;
|
||||
mod unix_socket;
|
||||
|
||||
pub use self::iovs::{Iovs, IovsMut, SliceAsLibcIovec};
|
||||
pub use self::msg::{msghdr, msghdr_mut, MsgHdr, MsgHdrMut};
|
||||
pub use self::msg_flags::MsgFlags;
|
||||
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 fs::{AsUnixSocket, File, FileDesc, FileRef, UnixSocketFile};
|
||||
use super::io_multiplexing;
|
||||
use fs::{File, FileDesc, FileRef};
|
||||
use process::Process;
|
||||
use util::mem_util::from_user;
|
||||
|
||||
@ -124,3 +125,114 @@ impl c_msghdr_ext for msghdr_mut {
|
||||
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 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::fmt;
|
||||
use std::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering};
|
@ -7,12 +7,9 @@
|
||||
//! 3. Dispatch the syscall to `do_*` (at this file)
|
||||
//! 4. Do some memory checks then call `mod::do_*` (at each module)
|
||||
|
||||
use fs::{
|
||||
AccessFlags, AccessModes, AsUnixSocket, FcntlCmd, File, FileDesc, FileRef, IoctlCmd,
|
||||
UnixSocketFile, AT_FDCWD,
|
||||
};
|
||||
use fs::{File, FileDesc, FileRef, Stat};
|
||||
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 std::ffi::{CStr, CString};
|
||||
use std::ptr;
|
||||
@ -72,81 +69,81 @@ pub extern "C" fn dispatch_syscall(
|
||||
|
||||
let ret = match num {
|
||||
// file
|
||||
SYS_OPEN => do_open(arg0 as *const i8, arg1 as u32, arg2 as u32),
|
||||
SYS_CLOSE => do_close(arg0 as FileDesc),
|
||||
SYS_READ => 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_PREAD64 => do_pread(
|
||||
SYS_OPEN => fs::do_open(arg0 as *const i8, arg1 as u32, arg2 as u32),
|
||||
SYS_CLOSE => fs::do_close(arg0 as FileDesc),
|
||||
SYS_READ => fs::do_read(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize),
|
||||
SYS_WRITE => fs::do_write(arg0 as FileDesc, arg1 as *const u8, arg2 as usize),
|
||||
SYS_PREAD64 => fs::do_pread(
|
||||
arg0 as FileDesc,
|
||||
arg1 as *mut u8,
|
||||
arg2 as usize,
|
||||
arg3 as usize,
|
||||
),
|
||||
SYS_PWRITE64 => do_pwrite(
|
||||
SYS_PWRITE64 => fs::do_pwrite(
|
||||
arg0 as FileDesc,
|
||||
arg1 as *const u8,
|
||||
arg2 as usize,
|
||||
arg3 as usize,
|
||||
),
|
||||
SYS_READV => do_readv(arg0 as FileDesc, arg1 as *mut iovec_t, arg2 as i32),
|
||||
SYS_WRITEV => do_writev(arg0 as FileDesc, arg1 as *mut iovec_t, arg2 as i32),
|
||||
SYS_STAT => do_stat(arg0 as *const i8, arg1 as *mut fs::Stat),
|
||||
SYS_FSTAT => do_fstat(arg0 as FileDesc, arg1 as *mut fs::Stat),
|
||||
SYS_LSTAT => do_lstat(arg0 as *const i8, arg1 as *mut fs::Stat),
|
||||
SYS_ACCESS => 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_LSEEK => do_lseek(arg0 as FileDesc, arg1 as off_t, arg2 as i32),
|
||||
SYS_FSYNC => do_fsync(arg0 as FileDesc),
|
||||
SYS_FDATASYNC => do_fdatasync(arg0 as FileDesc),
|
||||
SYS_TRUNCATE => do_truncate(arg0 as *const i8, arg1 as usize),
|
||||
SYS_FTRUNCATE => do_ftruncate(arg0 as FileDesc, arg1 as usize),
|
||||
SYS_GETDENTS64 => do_getdents64(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize),
|
||||
SYS_SYNC => do_sync(),
|
||||
SYS_READV => fs::do_readv(arg0 as FileDesc, arg1 as *mut fs::iovec_t, arg2 as i32),
|
||||
SYS_WRITEV => fs::do_writev(arg0 as FileDesc, arg1 as *mut fs::iovec_t, arg2 as i32),
|
||||
SYS_STAT => fs::do_stat(arg0 as *const i8, arg1 as *mut Stat),
|
||||
SYS_FSTAT => fs::do_fstat(arg0 as FileDesc, arg1 as *mut Stat),
|
||||
SYS_LSTAT => fs::do_lstat(arg0 as *const i8, arg1 as *mut Stat),
|
||||
SYS_ACCESS => fs::do_access(arg0 as *const i8, arg1 as u32),
|
||||
SYS_FACCESSAT => fs::do_faccessat(arg0 as i32, arg1 as *const i8, arg2 as u32, arg3 as u32),
|
||||
SYS_LSEEK => fs::do_lseek(arg0 as FileDesc, arg1 as off_t, arg2 as i32),
|
||||
SYS_FSYNC => fs::do_fsync(arg0 as FileDesc),
|
||||
SYS_FDATASYNC => fs::do_fdatasync(arg0 as FileDesc),
|
||||
SYS_TRUNCATE => fs::do_truncate(arg0 as *const i8, arg1 as usize),
|
||||
SYS_FTRUNCATE => fs::do_ftruncate(arg0 as FileDesc, arg1 as usize),
|
||||
SYS_GETDENTS64 => fs::do_getdents64(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize),
|
||||
SYS_SYNC => fs::do_sync(),
|
||||
SYS_GETCWD => do_getcwd(arg0 as *mut u8, arg1 as usize),
|
||||
SYS_CHDIR => do_chdir(arg0 as *mut i8),
|
||||
SYS_RENAME => do_rename(arg0 as *const i8, arg1 as *const i8),
|
||||
SYS_MKDIR => do_mkdir(arg0 as *const i8, arg1 as usize),
|
||||
SYS_RMDIR => do_rmdir(arg0 as *const i8),
|
||||
SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8),
|
||||
SYS_UNLINK => do_unlink(arg0 as *const i8),
|
||||
SYS_READLINK => do_readlink(arg0 as *const i8, arg1 as *mut u8, arg2 as usize),
|
||||
SYS_SENDFILE => do_sendfile(
|
||||
SYS_CHDIR => fs::do_chdir(arg0 as *mut i8),
|
||||
SYS_RENAME => fs::do_rename(arg0 as *const i8, arg1 as *const i8),
|
||||
SYS_MKDIR => fs::do_mkdir(arg0 as *const i8, arg1 as usize),
|
||||
SYS_RMDIR => fs::do_rmdir(arg0 as *const i8),
|
||||
SYS_LINK => fs::do_link(arg0 as *const i8, arg1 as *const i8),
|
||||
SYS_UNLINK => fs::do_unlink(arg0 as *const i8),
|
||||
SYS_READLINK => fs::do_readlink(arg0 as *const i8, arg1 as *mut u8, arg2 as usize),
|
||||
SYS_SENDFILE => fs::do_sendfile(
|
||||
arg0 as FileDesc,
|
||||
arg1 as FileDesc,
|
||||
arg2 as *mut off_t,
|
||||
arg3 as usize,
|
||||
),
|
||||
SYS_FCNTL => 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_FCNTL => fs::do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64),
|
||||
SYS_IOCTL => fs::do_ioctl(arg0 as FileDesc, arg1 as u32, arg2 as *mut u8),
|
||||
|
||||
// IO multiplexing
|
||||
SYS_SELECT => do_select(
|
||||
SYS_SELECT => net::do_select(
|
||||
arg0 as c_int,
|
||||
arg1 as *mut libc::fd_set,
|
||||
arg2 as *mut libc::fd_set,
|
||||
arg3 as *mut libc::fd_set,
|
||||
arg4 as *const libc::timeval,
|
||||
),
|
||||
SYS_POLL => do_poll(
|
||||
SYS_POLL => net::do_poll(
|
||||
arg0 as *mut libc::pollfd,
|
||||
arg1 as libc::nfds_t,
|
||||
arg2 as c_int,
|
||||
),
|
||||
SYS_EPOLL_CREATE => do_epoll_create(arg0 as c_int),
|
||||
SYS_EPOLL_CREATE1 => do_epoll_create1(arg0 as c_int),
|
||||
SYS_EPOLL_CTL => do_epoll_ctl(
|
||||
SYS_EPOLL_CREATE => net::do_epoll_create(arg0 as c_int),
|
||||
SYS_EPOLL_CREATE1 => net::do_epoll_create1(arg0 as c_int),
|
||||
SYS_EPOLL_CTL => net::do_epoll_ctl(
|
||||
arg0 as c_int,
|
||||
arg1 as c_int,
|
||||
arg2 as c_int,
|
||||
arg3 as *const libc::epoll_event,
|
||||
),
|
||||
SYS_EPOLL_WAIT => do_epoll_wait(
|
||||
SYS_EPOLL_WAIT => net::do_epoll_wait(
|
||||
arg0 as c_int,
|
||||
arg1 as *mut libc::epoll_event,
|
||||
arg2 as c_int,
|
||||
arg3 as c_int,
|
||||
),
|
||||
SYS_EPOLL_PWAIT => do_epoll_pwait(
|
||||
SYS_EPOLL_PWAIT => net::do_epoll_pwait(
|
||||
arg0 as c_int,
|
||||
arg1 as *mut libc::epoll_event,
|
||||
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_BRK => do_brk(arg0 as usize),
|
||||
|
||||
SYS_PIPE => do_pipe2(arg0 as *mut i32, 0),
|
||||
SYS_PIPE2 => do_pipe2(arg0 as *mut i32, arg1 as u32),
|
||||
SYS_DUP => do_dup(arg0 as FileDesc),
|
||||
SYS_DUP2 => do_dup2(arg0 as FileDesc, arg1 as FileDesc),
|
||||
SYS_DUP3 => do_dup3(arg0 as FileDesc, arg1 as FileDesc, arg2 as u32),
|
||||
SYS_PIPE => fs::do_pipe2(arg0 as *mut i32, 0),
|
||||
SYS_PIPE2 => fs::do_pipe2(arg0 as *mut i32, arg1 as u32),
|
||||
SYS_DUP => fs::do_dup(arg0 as FileDesc),
|
||||
SYS_DUP2 => fs::do_dup2(arg0 as FileDesc, arg1 as FileDesc),
|
||||
SYS_DUP3 => fs::do_dup3(arg0 as FileDesc, arg1 as FileDesc, arg2 as u32),
|
||||
|
||||
SYS_GETTIMEOFDAY => do_gettimeofday(arg0 as *mut timeval_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.
|
||||
* 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(
|
||||
addr: usize,
|
||||
size: usize,
|
||||
@ -817,32 +618,6 @@ fn do_getegid() -> Result<isize> {
|
||||
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
|
||||
fn do_gettimeofday(tv_u: *mut timeval_t) -> Result<isize> {
|
||||
check_mut_ptr(tv_u)?;
|
||||
@ -921,101 +696,6 @@ fn do_getcwd(buf: *mut u8, size: usize) -> Result<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> {
|
||||
let code = process::ArchPrctlCode::from_u32(code)?;
|
||||
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> {
|
||||
check_mut_ptr(name)?;
|
||||
let name = unsafe { &mut *name };
|
||||
@ -1549,26 +1118,6 @@ fn do_prlimit(
|
||||
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
|
||||
|
||||
fn do_rt_sigaction() -> Result<isize> {
|
||||
|
Loading…
Reference in New Issue
Block a user