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 super::*;
|
||||||
use std;
|
|
||||||
use std::borrow::BorrowMut;
|
|
||||||
use std::fmt;
|
|
||||||
use std::io::SeekFrom;
|
|
||||||
|
|
||||||
macro_rules! return_op_unsupported_error {
|
macro_rules! return_op_unsupported_error {
|
||||||
($op_name: expr, $errno: expr) => {{
|
($op_name: expr, $errno: expr) => {{
|
||||||
@ -88,436 +84,6 @@ pub trait File: Debug + Sync + Send + Any {
|
|||||||
|
|
||||||
pub type FileRef = Arc<Box<dyn File>>;
|
pub type FileRef = Arc<Box<dyn File>>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct SgxFile {
|
|
||||||
inner: SgxMutex<SgxFileInner>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SgxFile {
|
|
||||||
pub fn new(
|
|
||||||
file: Arc<SgxMutex<fs_impl::SgxFile>>,
|
|
||||||
is_readable: bool,
|
|
||||||
is_writable: bool,
|
|
||||||
is_append: bool,
|
|
||||||
) -> Result<SgxFile> {
|
|
||||||
if !is_readable && !is_writable {
|
|
||||||
return_errno!(EINVAL, "Invalid permissions");
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(SgxFile {
|
|
||||||
inner: SgxMutex::new(SgxFileInner {
|
|
||||||
pos: 0 as usize,
|
|
||||||
file: file,
|
|
||||||
is_readable,
|
|
||||||
is_writable,
|
|
||||||
is_append,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl File for SgxFile {
|
|
||||||
fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
let mut inner_guard = self.inner.lock().unwrap();
|
|
||||||
let inner = inner_guard.borrow_mut();
|
|
||||||
inner.read(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write(&self, buf: &[u8]) -> Result<usize> {
|
|
||||||
let mut inner_guard = self.inner.lock().unwrap();
|
|
||||||
let inner = inner_guard.borrow_mut();
|
|
||||||
inner.write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
let mut inner_guard = self.inner.lock().unwrap();
|
|
||||||
let inner = inner_guard.borrow_mut();
|
|
||||||
inner.seek(SeekFrom::Start(offset as u64))?;
|
|
||||||
inner.read(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize> {
|
|
||||||
let mut inner_guard = self.inner.lock().unwrap();
|
|
||||||
let inner = inner_guard.borrow_mut();
|
|
||||||
inner.seek(SeekFrom::Start(offset as u64))?;
|
|
||||||
inner.write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
|
|
||||||
let mut inner_guard = self.inner.lock().unwrap();
|
|
||||||
let inner = inner_guard.borrow_mut();
|
|
||||||
inner.readv(bufs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
|
|
||||||
let mut inner_guard = self.inner.lock().unwrap();
|
|
||||||
let inner = inner_guard.borrow_mut();
|
|
||||||
inner.writev(bufs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn seek(&self, pos: SeekFrom) -> Result<off_t> {
|
|
||||||
let mut inner_guard = self.inner.lock().unwrap();
|
|
||||||
let inner = inner_guard.borrow_mut();
|
|
||||||
inner.seek(pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
#[repr(C)]
|
|
||||||
struct SgxFileInner {
|
|
||||||
// perms: FilePerms,
|
|
||||||
pos: usize,
|
|
||||||
file: Arc<SgxMutex<fs_impl::SgxFile>>,
|
|
||||||
is_readable: bool,
|
|
||||||
is_writable: bool,
|
|
||||||
is_append: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SgxFileInner {
|
|
||||||
pub fn write(&mut self, buf: &[u8]) -> Result<usize> {
|
|
||||||
if !self.is_writable {
|
|
||||||
return_errno!(EINVAL, "File not writable");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut file_guard = self.file.lock().unwrap();
|
|
||||||
let file = file_guard.borrow_mut();
|
|
||||||
|
|
||||||
let seek_pos = if !self.is_append {
|
|
||||||
SeekFrom::Start(self.pos as u64)
|
|
||||||
} else {
|
|
||||||
SeekFrom::End(0)
|
|
||||||
};
|
|
||||||
// TODO: recover from error
|
|
||||||
file.seek(seek_pos).map_err(|e| errno!(e))?;
|
|
||||||
|
|
||||||
let write_len = { file.write(buf).map_err(|e| errno!(e))? };
|
|
||||||
|
|
||||||
if !self.is_append {
|
|
||||||
self.pos += write_len;
|
|
||||||
}
|
|
||||||
Ok(write_len)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
if !self.is_readable {
|
|
||||||
return_errno!(EINVAL, "File not readable");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut file_guard = self.file.lock().unwrap();
|
|
||||||
let file = file_guard.borrow_mut();
|
|
||||||
|
|
||||||
let seek_pos = SeekFrom::Start(self.pos as u64);
|
|
||||||
file.seek(seek_pos).map_err(|e| errno!(e))?;
|
|
||||||
|
|
||||||
let read_len = { file.read(buf).map_err(|e| errno!(e))? };
|
|
||||||
|
|
||||||
self.pos += read_len;
|
|
||||||
Ok(read_len)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn seek(&mut self, pos: SeekFrom) -> Result<off_t> {
|
|
||||||
let mut file_guard = self.file.lock().unwrap();
|
|
||||||
let file = file_guard.borrow_mut();
|
|
||||||
|
|
||||||
let pos = match pos {
|
|
||||||
SeekFrom::Start(absolute_offset) => pos,
|
|
||||||
SeekFrom::End(relative_offset) => pos,
|
|
||||||
SeekFrom::Current(relative_offset) => {
|
|
||||||
if relative_offset >= 0 {
|
|
||||||
SeekFrom::Start((self.pos + relative_offset as usize) as u64)
|
|
||||||
} else {
|
|
||||||
let backward_offset = (-relative_offset) as usize;
|
|
||||||
if self.pos < backward_offset {
|
|
||||||
// underflow
|
|
||||||
return_errno!(EINVAL, "Invalid seek position");
|
|
||||||
}
|
|
||||||
SeekFrom::Start((self.pos - backward_offset) as u64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.pos = file.seek(pos).map_err(|e| errno!(e))? as usize;
|
|
||||||
Ok(self.pos as off_t)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn writev(&mut self, bufs: &[&[u8]]) -> Result<usize> {
|
|
||||||
if !self.is_writable {
|
|
||||||
return_errno!(EINVAL, "File not writable");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut file_guard = self.file.lock().unwrap();
|
|
||||||
let file = file_guard.borrow_mut();
|
|
||||||
|
|
||||||
let seek_pos = if !self.is_append {
|
|
||||||
SeekFrom::Start(self.pos as u64)
|
|
||||||
} else {
|
|
||||||
SeekFrom::End(0)
|
|
||||||
};
|
|
||||||
file.seek(seek_pos).map_err(|e| errno!(e))?;
|
|
||||||
|
|
||||||
let mut total_bytes = 0;
|
|
||||||
for buf in bufs {
|
|
||||||
match file.write(buf) {
|
|
||||||
Ok(this_bytes) => {
|
|
||||||
total_bytes += this_bytes;
|
|
||||||
if this_bytes < buf.len() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
match total_bytes {
|
|
||||||
// a complete failure
|
|
||||||
0 => return_errno!(EINVAL, "Failed to write"),
|
|
||||||
// a partially failure
|
|
||||||
_ => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.pos += total_bytes;
|
|
||||||
Ok(total_bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn readv(&mut self, bufs: &mut [&mut [u8]]) -> Result<usize> {
|
|
||||||
if !self.is_readable {
|
|
||||||
return_errno!(EINVAL, "File not readable");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut file_guard = self.file.lock().unwrap();
|
|
||||||
let file = file_guard.borrow_mut();
|
|
||||||
|
|
||||||
let seek_pos = SeekFrom::Start(self.pos as u64);
|
|
||||||
file.seek(seek_pos).map_err(|e| errno!(e))?;
|
|
||||||
|
|
||||||
let mut total_bytes = 0;
|
|
||||||
for buf in bufs {
|
|
||||||
match file.read(buf) {
|
|
||||||
Ok(this_bytes) => {
|
|
||||||
total_bytes += this_bytes;
|
|
||||||
if this_bytes < buf.len() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
match total_bytes {
|
|
||||||
// a complete failure
|
|
||||||
0 => return_errno!(EINVAL, "Failed to write"),
|
|
||||||
// a partially failure
|
|
||||||
_ => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.pos += total_bytes;
|
|
||||||
Ok(total_bytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Send for SgxFileInner {}
|
|
||||||
unsafe impl Sync for SgxFileInner {}
|
|
||||||
|
|
||||||
impl Debug for SgxFileInner {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "SgxFileInner {{ pos: {}, file: ??? }}", self.pos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct StdoutFile {
|
|
||||||
inner: std::io::Stdout,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StdoutFile {
|
|
||||||
pub fn new() -> StdoutFile {
|
|
||||||
StdoutFile {
|
|
||||||
inner: std::io::stdout(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl File for StdoutFile {
|
|
||||||
fn write(&self, buf: &[u8]) -> Result<usize> {
|
|
||||||
let write_len = { self.inner.lock().write(buf).map_err(|e| errno!(e))? };
|
|
||||||
Ok(write_len)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_at(&self, _offset: usize, buf: &[u8]) -> Result<usize> {
|
|
||||||
self.write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn writev(&self, bufs: &[&[u8]]) -> Result<usize> {
|
|
||||||
let mut guard = self.inner.lock();
|
|
||||||
let mut total_bytes = 0;
|
|
||||||
for buf in bufs {
|
|
||||||
match guard.write(buf) {
|
|
||||||
Ok(this_len) => {
|
|
||||||
total_bytes += this_len;
|
|
||||||
if this_len < buf.len() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
match total_bytes {
|
|
||||||
// a complete failure
|
|
||||||
0 => return_errno!(EINVAL, "Failed to write"),
|
|
||||||
// a partially failure
|
|
||||||
_ => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(total_bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn metadata(&self) -> Result<Metadata> {
|
|
||||||
Ok(Metadata {
|
|
||||||
dev: 0,
|
|
||||||
inode: 0,
|
|
||||||
size: 0,
|
|
||||||
blk_size: 0,
|
|
||||||
blocks: 0,
|
|
||||||
atime: Timespec { sec: 0, nsec: 0 },
|
|
||||||
mtime: Timespec { sec: 0, nsec: 0 },
|
|
||||||
ctime: Timespec { sec: 0, nsec: 0 },
|
|
||||||
type_: FileType::CharDevice,
|
|
||||||
mode: 0,
|
|
||||||
nlinks: 0,
|
|
||||||
uid: 0,
|
|
||||||
gid: 0,
|
|
||||||
rdev: 0,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sync_all(&self) -> Result<()> {
|
|
||||||
self.sync_data()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sync_data(&self) -> Result<()> {
|
|
||||||
self.inner.lock().flush()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ioctl(&self, cmd: &mut IoctlCmd) -> Result<()> {
|
|
||||||
let can_delegate_to_host = match cmd {
|
|
||||||
IoctlCmd::TIOCGWINSZ(_) => true,
|
|
||||||
IoctlCmd::TIOCSWINSZ(_) => true,
|
|
||||||
_ => false,
|
|
||||||
};
|
|
||||||
if !can_delegate_to_host {
|
|
||||||
return_errno!(EINVAL, "unknown ioctl cmd for stdout");
|
|
||||||
}
|
|
||||||
|
|
||||||
let cmd_bits = cmd.cmd_num() as c_int;
|
|
||||||
let cmd_arg_ptr = cmd.arg_ptr() as *const c_int;
|
|
||||||
let host_stdout_fd = {
|
|
||||||
use std::os::unix::io::AsRawFd;
|
|
||||||
self.inner.as_raw_fd() as i32
|
|
||||||
};
|
|
||||||
try_libc!(libc::ocall::ioctl_arg1(
|
|
||||||
host_stdout_fd,
|
|
||||||
cmd_bits,
|
|
||||||
cmd_arg_ptr
|
|
||||||
));
|
|
||||||
cmd.validate_arg_val()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for StdoutFile {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "StdoutFile")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Send for StdoutFile {}
|
|
||||||
unsafe impl Sync for StdoutFile {}
|
|
||||||
|
|
||||||
pub struct StdinFile {
|
|
||||||
inner: std::io::Stdin,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StdinFile {
|
|
||||||
pub fn new() -> StdinFile {
|
|
||||||
StdinFile {
|
|
||||||
inner: std::io::stdin(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl File for StdinFile {
|
|
||||||
fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
let read_len = { self.inner.lock().read(buf).map_err(|e| errno!(e))? };
|
|
||||||
Ok(read_len)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn readv(&self, bufs: &mut [&mut [u8]]) -> Result<usize> {
|
|
||||||
let mut guard = self.inner.lock();
|
|
||||||
let mut total_bytes = 0;
|
|
||||||
for buf in bufs {
|
|
||||||
match guard.read(buf) {
|
|
||||||
Ok(this_len) => {
|
|
||||||
total_bytes += this_len;
|
|
||||||
if this_len < buf.len() {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
match total_bytes {
|
|
||||||
// a complete failure
|
|
||||||
0 => return_errno!(EINVAL, "Failed to write"),
|
|
||||||
// a partially failure
|
|
||||||
_ => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(total_bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn metadata(&self) -> Result<Metadata> {
|
|
||||||
Ok(Metadata {
|
|
||||||
dev: 0,
|
|
||||||
inode: 0,
|
|
||||||
size: 0,
|
|
||||||
blk_size: 0,
|
|
||||||
blocks: 0,
|
|
||||||
atime: Timespec { sec: 0, nsec: 0 },
|
|
||||||
mtime: Timespec { sec: 0, nsec: 0 },
|
|
||||||
ctime: Timespec { sec: 0, nsec: 0 },
|
|
||||||
type_: FileType::CharDevice,
|
|
||||||
mode: 0,
|
|
||||||
nlinks: 0,
|
|
||||||
uid: 0,
|
|
||||||
gid: 0,
|
|
||||||
rdev: 0,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for StdinFile {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "StdinFile")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Send for StdinFile {}
|
|
||||||
unsafe impl Sync for StdinFile {}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
struct FileOpNotSupportedError {
|
struct FileOpNotSupportedError {
|
||||||
errno: Errno,
|
errno: Errno,
|
||||||
|
@ -1,32 +1,29 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
//int faccessat(int dirfd, const char *pathname, int mode, int flags);
|
|
||||||
//int access(const char *pathname, int mode);
|
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub struct AccessModes : u32 {
|
pub struct AccessibilityCheckMode : u32 {
|
||||||
const X_OK = 1;
|
const X_OK = 1;
|
||||||
const W_OK = 2;
|
const W_OK = 2;
|
||||||
const R_OK = 4;
|
const R_OK = 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AccessModes {
|
impl AccessibilityCheckMode {
|
||||||
pub fn from_u32(bits: u32) -> Result<AccessModes> {
|
pub fn from_u32(bits: u32) -> Result<AccessibilityCheckMode> {
|
||||||
AccessModes::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid mode"))
|
AccessibilityCheckMode::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid mode"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub struct AccessFlags : u32 {
|
pub struct AccessibilityCheckFlags : u32 {
|
||||||
const AT_SYMLINK_NOFOLLOW = 0x100;
|
const AT_SYMLINK_NOFOLLOW = 0x100;
|
||||||
const AT_EACCESS = 0x200;
|
const AT_EACCESS = 0x200;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AccessFlags {
|
impl AccessibilityCheckFlags {
|
||||||
pub fn from_u32(bits: u32) -> Result<AccessFlags> {
|
pub fn from_u32(bits: u32) -> Result<AccessibilityCheckFlags> {
|
||||||
AccessFlags::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid flags"))
|
AccessibilityCheckFlags::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid flags"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,8 +32,8 @@ pub const AT_FDCWD: i32 = -100;
|
|||||||
pub fn do_faccessat(
|
pub fn do_faccessat(
|
||||||
dirfd: Option<FileDesc>,
|
dirfd: Option<FileDesc>,
|
||||||
path: &str,
|
path: &str,
|
||||||
mode: AccessModes,
|
mode: AccessibilityCheckMode,
|
||||||
flags: AccessFlags,
|
flags: AccessibilityCheckFlags,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
info!(
|
info!(
|
||||||
"faccessat: dirfd: {:?}, path: {:?}, mode: {:?}, flags: {:?}",
|
"faccessat: dirfd: {:?}, path: {:?}, mode: {:?}, flags: {:?}",
|
||||||
@ -49,7 +46,7 @@ pub fn do_faccessat(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_access(path: &str, mode: AccessModes) -> Result<()> {
|
pub fn do_access(path: &str, mode: AccessibilityCheckMode) -> Result<()> {
|
||||||
info!("access: path: {:?}, mode: {:?}", path, mode);
|
info!("access: path: {:?}, mode: {:?}", path, mode);
|
||||||
let current_ref = process::get_current();
|
let current_ref = process::get_current();
|
||||||
let mut current = current_ref.lock().unwrap();
|
let mut current = current_ref.lock().unwrap();
|
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 super::*;
|
||||||
use process::FileTableRef;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FcntlCmd {
|
pub enum FcntlCmd {
|
||||||
@ -34,7 +33,11 @@ impl FcntlCmd {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn do_fcntl(file_table_ref: &FileTableRef, fd: FileDesc, cmd: &FcntlCmd) -> Result<isize> {
|
pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result<isize> {
|
||||||
|
info!("fcntl: fd: {:?}, cmd: {:?}", &fd, cmd);
|
||||||
|
let current_ref = process::get_current();
|
||||||
|
let mut current = current_ref.lock().unwrap();
|
||||||
|
let file_table_ref = current.get_files();
|
||||||
let mut file_table = file_table_ref.lock().unwrap();
|
let mut file_table = file_table_ref.lock().unwrap();
|
||||||
let ret = match cmd {
|
let ret = match cmd {
|
||||||
FcntlCmd::DupFd(min_fd) => {
|
FcntlCmd::DupFd(min_fd) => {
|
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(())
|
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 super::*;
|
||||||
use std;
|
|
||||||
|
|
||||||
pub type FileDesc = u32;
|
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 super::*;
|
||||||
use rcore_fs_sefs::dev::SefsMac;
|
use rcore_fs_sefs::dev::SefsMac;
|
||||||
use sgx_trts::libc::S_IRUSR;
|
use sgx_trts::libc::{S_IRUSR, S_IWUSR};
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
pub struct INodeFile {
|
pub struct INodeFile {
|
||||||
inode: Arc<dyn INode>,
|
inode: Arc<dyn INode>,
|
||||||
|
@ -1,756 +1,32 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use net::{AsSocket, SocketFile};
|
use process;
|
||||||
use process::Process;
|
use rcore_fs::vfs::{FileSystem, FileType, FsError, INode, Metadata, Timespec};
|
||||||
use rcore_fs::vfs::{FileType, FsError, INode, Metadata, Timespec};
|
use std;
|
||||||
use std::io::{Read, Seek, SeekFrom, Write};
|
|
||||||
use std::sgxfs as fs_impl;
|
|
||||||
use {process, std};
|
|
||||||
|
|
||||||
pub use self::access::{do_access, do_faccessat, AccessFlags, AccessModes, AT_FDCWD};
|
|
||||||
use self::dev_null::DevNull;
|
|
||||||
use self::dev_random::DevRandom;
|
|
||||||
use self::dev_sgx::DevSgx;
|
|
||||||
use self::dev_zero::DevZero;
|
|
||||||
pub use self::fcntl::FcntlCmd;
|
|
||||||
pub use self::file::{File, FileRef, SgxFile, StdinFile, StdoutFile};
|
|
||||||
pub use self::file_flags::{AccessMode, CreationFlags, StatusFlags};
|
|
||||||
pub use self::file_table::{FileDesc, FileTable};
|
|
||||||
pub use self::inode_file::{AsINodeFile, INodeExt, INodeFile};
|
|
||||||
pub use self::io_multiplexing::*;
|
|
||||||
pub use self::ioctl::*;
|
|
||||||
pub use self::pipe::Pipe;
|
|
||||||
pub use self::root_inode::ROOT_INODE;
|
|
||||||
pub use self::unix_socket::{AsUnixSocket, UnixSocketFile};
|
|
||||||
use sgx_trts::libc::S_IWUSR;
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
|
use std::fmt;
|
||||||
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
|
|
||||||
mod access;
|
pub use self::file::{File, FileRef};
|
||||||
mod dev_null;
|
pub use self::file_ops::{AccessMode, CreationFlags, Stat, StatusFlags};
|
||||||
mod dev_random;
|
pub use self::file_ops::{IoctlCmd, StructuredIoctlArgType, StructuredIoctlNum};
|
||||||
mod dev_sgx;
|
pub use self::file_table::{FileDesc, FileTable};
|
||||||
mod dev_zero;
|
pub use self::inode_file::{AsINodeFile, INodeExt, INodeFile};
|
||||||
mod fcntl;
|
pub use self::pipe::Pipe;
|
||||||
|
pub use self::rootfs::ROOT_INODE;
|
||||||
|
pub use self::stdio::{StdinFile, StdoutFile};
|
||||||
|
pub use self::syscalls::*;
|
||||||
|
|
||||||
|
mod dev_fs;
|
||||||
mod file;
|
mod file;
|
||||||
mod file_flags;
|
mod file_ops;
|
||||||
mod file_table;
|
mod file_table;
|
||||||
|
mod fs_ops;
|
||||||
mod hostfs;
|
mod hostfs;
|
||||||
mod inode_file;
|
mod inode_file;
|
||||||
mod io_multiplexing;
|
|
||||||
mod ioctl;
|
|
||||||
mod pipe;
|
mod pipe;
|
||||||
mod root_inode;
|
mod rootfs;
|
||||||
mod sgx_impl;
|
mod sefs;
|
||||||
mod unix_socket;
|
mod stdio;
|
||||||
|
mod syscalls;
|
||||||
pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc> {
|
|
||||||
info!(
|
|
||||||
"open: path: {:?}, flags: {:#o}, mode: {:#o}",
|
|
||||||
path, flags, mode
|
|
||||||
);
|
|
||||||
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let mut proc = current_ref.lock().unwrap();
|
|
||||||
|
|
||||||
let file = proc.open_file(path, flags, mode)?;
|
|
||||||
let file_ref: Arc<Box<dyn File>> = Arc::new(file);
|
|
||||||
|
|
||||||
let fd = {
|
|
||||||
let creation_flags = CreationFlags::from_bits_truncate(flags);
|
|
||||||
proc.get_files()
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.put(file_ref, creation_flags.must_close_on_spawn())
|
|
||||||
};
|
|
||||||
Ok(fd)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_write(fd: FileDesc, buf: &[u8]) -> Result<usize> {
|
|
||||||
info!("write: fd: {}", fd);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
|
||||||
file_ref.write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_read(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
info!("read: fd: {}", fd);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
|
||||||
file_ref.read(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_writev(fd: FileDesc, bufs: &[&[u8]]) -> Result<usize> {
|
|
||||||
info!("writev: fd: {}", fd);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
|
||||||
file_ref.writev(bufs)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_readv(fd: FileDesc, bufs: &mut [&mut [u8]]) -> Result<usize> {
|
|
||||||
info!("readv: fd: {}", fd);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
|
||||||
file_ref.readv(bufs)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_pwrite(fd: FileDesc, buf: &[u8], offset: usize) -> Result<usize> {
|
|
||||||
info!("pwrite: fd: {}, offset: {}", fd, offset);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
|
||||||
file_ref.write_at(offset, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_pread(fd: FileDesc, buf: &mut [u8], offset: usize) -> Result<usize> {
|
|
||||||
info!("pread: fd: {}, offset: {}", fd, offset);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
|
||||||
file_ref.read_at(offset, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_stat(path: &str) -> Result<Stat> {
|
|
||||||
warn!("stat is partial implemented as lstat");
|
|
||||||
do_lstat(path)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_fstat(fd: u32) -> Result<Stat> {
|
|
||||||
info!("fstat: fd: {}", fd);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
|
||||||
let stat = Stat::from(file_ref.metadata()?);
|
|
||||||
// TODO: handle symlink
|
|
||||||
Ok(stat)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_lstat(path: &str) -> Result<Stat> {
|
|
||||||
info!("lstat: path: {}", path);
|
|
||||||
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
let inode = current_process.lookup_inode(&path)?;
|
|
||||||
let stat = Stat::from(inode.metadata()?);
|
|
||||||
Ok(stat)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_lseek(fd: FileDesc, offset: SeekFrom) -> Result<off_t> {
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
|
||||||
file_ref.seek(offset)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_fsync(fd: FileDesc) -> Result<()> {
|
|
||||||
info!("fsync: fd: {}", fd);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
|
||||||
file_ref.sync_all()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_fdatasync(fd: FileDesc) -> Result<()> {
|
|
||||||
info!("fdatasync: fd: {}", fd);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
|
||||||
file_ref.sync_data()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_truncate(path: &str, len: usize) -> Result<()> {
|
|
||||||
info!("truncate: path: {:?}, len: {}", path, len);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
current_process.lookup_inode(&path)?.resize(len)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_ftruncate(fd: FileDesc, len: usize) -> Result<()> {
|
|
||||||
info!("ftruncate: fd: {}, len: {}", fd, len);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
|
||||||
file_ref.set_len(len as u64)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_getdents64(fd: FileDesc, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
info!(
|
|
||||||
"getdents64: fd: {}, buf: {:?}, buf_size: {}",
|
|
||||||
fd,
|
|
||||||
buf.as_ptr(),
|
|
||||||
buf.len()
|
|
||||||
);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
|
||||||
let info = file_ref.metadata()?;
|
|
||||||
if info.type_ != FileType::Dir {
|
|
||||||
return_errno!(ENOTDIR, "");
|
|
||||||
}
|
|
||||||
let mut writer = unsafe { DirentBufWriter::new(buf) };
|
|
||||||
loop {
|
|
||||||
let name = match file_ref.read_entry() {
|
|
||||||
Err(e) => {
|
|
||||||
let errno = e.errno();
|
|
||||||
if errno == ENOENT {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return Err(e.cause_err(|_| errno!(errno, "failed to read entry")));
|
|
||||||
}
|
|
||||||
Ok(name) => name,
|
|
||||||
};
|
|
||||||
// TODO: get ino from dirent
|
|
||||||
if let Err(e) = writer.try_write(0, 0, &name) {
|
|
||||||
file_ref.seek(SeekFrom::Current(-1))?;
|
|
||||||
if writer.written_size == 0 {
|
|
||||||
return Err(e);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(writer.written_size)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_close(fd: FileDesc) -> Result<()> {
|
|
||||||
info!("close: fd: {}", fd);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
let file_table_ref = current_process.get_files();
|
|
||||||
let mut file_table = file_table_ref.lock().unwrap();
|
|
||||||
file_table.del(fd)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_ioctl(fd: FileDesc, cmd: &mut IoctlCmd) -> Result<()> {
|
|
||||||
info!("ioctl: fd: {}, cmd: {:?}", fd, cmd);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
let file_ref = current_process.get_files().lock().unwrap().get(fd)?;
|
|
||||||
file_ref.ioctl(cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2]> {
|
|
||||||
info!("pipe2: flags: {:#x}", flags);
|
|
||||||
let creation_flags = CreationFlags::from_bits_truncate(flags);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current = current_ref.lock().unwrap();
|
|
||||||
let pipe = Pipe::new(StatusFlags::from_bits_truncate(flags))?;
|
|
||||||
|
|
||||||
let file_table_ref = current.get_files();
|
|
||||||
let mut file_table = file_table_ref.lock().unwrap();
|
|
||||||
let close_on_spawn = creation_flags.must_close_on_spawn();
|
|
||||||
let reader_fd = file_table.put(Arc::new(Box::new(pipe.reader)), close_on_spawn);
|
|
||||||
let writer_fd = file_table.put(Arc::new(Box::new(pipe.writer)), close_on_spawn);
|
|
||||||
info!("pipe2: reader_fd: {}, writer_fd: {}", reader_fd, writer_fd);
|
|
||||||
Ok([reader_fd, writer_fd])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_dup(old_fd: FileDesc) -> Result<FileDesc> {
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current = current_ref.lock().unwrap();
|
|
||||||
let file_table_ref = current.get_files();
|
|
||||||
let mut file_table = file_table_ref.lock().unwrap();
|
|
||||||
let file = file_table.get(old_fd)?;
|
|
||||||
let new_fd = file_table.put(file, false);
|
|
||||||
Ok(new_fd)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result<FileDesc> {
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current = current_ref.lock().unwrap();
|
|
||||||
let file_table_ref = current.get_files();
|
|
||||||
let mut file_table = file_table_ref.lock().unwrap();
|
|
||||||
let file = file_table.get(old_fd)?;
|
|
||||||
if old_fd != new_fd {
|
|
||||||
file_table.put_at(new_fd, file, false);
|
|
||||||
}
|
|
||||||
Ok(new_fd)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_dup3(old_fd: FileDesc, new_fd: FileDesc, flags: u32) -> Result<FileDesc> {
|
|
||||||
let creation_flags = CreationFlags::from_bits_truncate(flags);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current = current_ref.lock().unwrap();
|
|
||||||
let file_table_ref = current.get_files();
|
|
||||||
let mut file_table = file_table_ref.lock().unwrap();
|
|
||||||
let file = file_table.get(old_fd)?;
|
|
||||||
if old_fd == new_fd {
|
|
||||||
return_errno!(EINVAL, "old_fd must not be equal to new_fd");
|
|
||||||
}
|
|
||||||
file_table.put_at(new_fd, file, creation_flags.must_close_on_spawn());
|
|
||||||
Ok(new_fd)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_sync() -> Result<()> {
|
|
||||||
info!("sync:");
|
|
||||||
ROOT_INODE.fs().sync()?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_chdir(path: &str) -> Result<()> {
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let mut current_process = current_ref.lock().unwrap();
|
|
||||||
info!("chdir: path: {:?}", path);
|
|
||||||
|
|
||||||
let inode = current_process.lookup_inode(path)?;
|
|
||||||
let info = inode.metadata()?;
|
|
||||||
if info.type_ != FileType::Dir {
|
|
||||||
return_errno!(ENOTDIR, "");
|
|
||||||
}
|
|
||||||
current_process.change_cwd(path);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_rename(oldpath: &str, newpath: &str) -> Result<()> {
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
info!("rename: oldpath: {:?}, newpath: {:?}", oldpath, newpath);
|
|
||||||
|
|
||||||
let (old_dir_path, old_file_name) = split_path(&oldpath);
|
|
||||||
let (new_dir_path, new_file_name) = split_path(&newpath);
|
|
||||||
let old_dir_inode = current_process.lookup_inode(old_dir_path)?;
|
|
||||||
let new_dir_inode = current_process.lookup_inode(new_dir_path)?;
|
|
||||||
// TODO: support to modify file's absolute path
|
|
||||||
old_dir_inode.move_(old_file_name, &new_dir_inode, new_file_name)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_mkdir(path: &str, mode: usize) -> Result<()> {
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
// TODO: check pathname
|
|
||||||
info!("mkdir: path: {:?}, mode: {:#o}", path, mode);
|
|
||||||
|
|
||||||
let (dir_path, file_name) = split_path(&path);
|
|
||||||
let inode = current_process.lookup_inode(dir_path)?;
|
|
||||||
if inode.find(file_name).is_ok() {
|
|
||||||
return_errno!(EEXIST, "");
|
|
||||||
}
|
|
||||||
if !inode.allow_write()? {
|
|
||||||
return_errno!(EPERM, "dir cannot be written");
|
|
||||||
}
|
|
||||||
inode.create(file_name, FileType::Dir, mode as u32)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_rmdir(path: &str) -> Result<()> {
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
info!("rmdir: path: {:?}", path);
|
|
||||||
|
|
||||||
let (dir_path, file_name) = split_path(&path);
|
|
||||||
let dir_inode = current_process.lookup_inode(dir_path)?;
|
|
||||||
let file_inode = dir_inode.find(file_name)?;
|
|
||||||
if file_inode.metadata()?.type_ != FileType::Dir {
|
|
||||||
return_errno!(ENOTDIR, "rmdir on not directory");
|
|
||||||
}
|
|
||||||
dir_inode.unlink(file_name)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_link(oldpath: &str, newpath: &str) -> Result<()> {
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
info!("link: oldpath: {:?}, newpath: {:?}", oldpath, newpath);
|
|
||||||
|
|
||||||
let (new_dir_path, new_file_name) = split_path(&newpath);
|
|
||||||
let inode = current_process.lookup_inode(&oldpath)?;
|
|
||||||
let new_dir_inode = current_process.lookup_inode(new_dir_path)?;
|
|
||||||
new_dir_inode.link(new_file_name, &inode)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_unlink(path: &str) -> Result<()> {
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
info!("unlink: path: {:?}", path);
|
|
||||||
|
|
||||||
let (dir_path, file_name) = split_path(&path);
|
|
||||||
let dir_inode = current_process.lookup_inode(dir_path)?;
|
|
||||||
let file_inode = dir_inode.find(file_name)?;
|
|
||||||
if file_inode.metadata()?.type_ == FileType::Dir {
|
|
||||||
return_errno!(EISDIR, "unlink on directory");
|
|
||||||
}
|
|
||||||
dir_inode.unlink(file_name)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_sendfile(
|
|
||||||
out_fd: FileDesc,
|
|
||||||
in_fd: FileDesc,
|
|
||||||
offset: Option<off_t>,
|
|
||||||
count: usize,
|
|
||||||
) -> Result<(usize, usize)> {
|
|
||||||
// (len, offset)
|
|
||||||
info!(
|
|
||||||
"sendfile: out: {}, in: {}, offset: {:?}, count: {}",
|
|
||||||
out_fd, in_fd, offset, count
|
|
||||||
);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current_process = current_ref.lock().unwrap();
|
|
||||||
let file_table_ref = current_process.get_files();
|
|
||||||
let mut file_table = file_table_ref.lock().unwrap();
|
|
||||||
|
|
||||||
let in_file = file_table.get(in_fd)?;
|
|
||||||
let out_file = file_table.get(out_fd)?;
|
|
||||||
let mut buffer: [u8; 1024 * 11] = unsafe { MaybeUninit::uninit().assume_init() };
|
|
||||||
|
|
||||||
let mut read_offset = match offset {
|
|
||||||
Some(offset) => offset,
|
|
||||||
None => in_file.seek(SeekFrom::Current(0))?,
|
|
||||||
} as usize;
|
|
||||||
|
|
||||||
// read from specified offset and write new offset back
|
|
||||||
let mut bytes_read = 0;
|
|
||||||
while bytes_read < count {
|
|
||||||
let len = min(buffer.len(), count - bytes_read);
|
|
||||||
let read_len = in_file.read_at(read_offset, &mut buffer[..len])?;
|
|
||||||
if read_len == 0 {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
bytes_read += read_len;
|
|
||||||
read_offset += read_len;
|
|
||||||
let mut bytes_written = 0;
|
|
||||||
while bytes_written < read_len {
|
|
||||||
let write_len = out_file.write(&buffer[bytes_written..])?;
|
|
||||||
if write_len == 0 {
|
|
||||||
return_errno!(EBADF, "sendfile write return 0");
|
|
||||||
}
|
|
||||||
bytes_written += write_len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if offset.is_none() {
|
|
||||||
in_file.seek(SeekFrom::Current(bytes_read as i64))?;
|
|
||||||
}
|
|
||||||
Ok((bytes_read, read_offset))
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
fn occlum_ocall_sync() -> sgx_status_t;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Process {
|
|
||||||
/// Open a file on the process. But DO NOT add it to file table.
|
|
||||||
pub fn open_file(&self, path: &str, flags: u32, mode: u32) -> Result<Box<dyn File>> {
|
|
||||||
if path == "/dev/null" {
|
|
||||||
return Ok(Box::new(DevNull));
|
|
||||||
}
|
|
||||||
if path == "/dev/zero" {
|
|
||||||
return Ok(Box::new(DevZero));
|
|
||||||
}
|
|
||||||
if path == "/dev/random" || path == "/dev/urandom" || path == "/dev/arandom" {
|
|
||||||
return Ok(Box::new(DevRandom));
|
|
||||||
}
|
|
||||||
if path == "/dev/sgx" {
|
|
||||||
return Ok(Box::new(DevSgx));
|
|
||||||
}
|
|
||||||
let creation_flags = CreationFlags::from_bits_truncate(flags);
|
|
||||||
let inode = if creation_flags.can_create() {
|
|
||||||
let (dir_path, file_name) = split_path(&path);
|
|
||||||
let dir_inode = self.lookup_inode(dir_path)?;
|
|
||||||
match dir_inode.find(file_name) {
|
|
||||||
Ok(file_inode) => {
|
|
||||||
if creation_flags.is_exclusive() {
|
|
||||||
return_errno!(EEXIST, "file exists");
|
|
||||||
}
|
|
||||||
file_inode
|
|
||||||
}
|
|
||||||
Err(FsError::EntryNotFound) => {
|
|
||||||
if !dir_inode.allow_write()? {
|
|
||||||
return_errno!(EPERM, "file cannot be created");
|
|
||||||
}
|
|
||||||
dir_inode.create(file_name, FileType::File, mode)?
|
|
||||||
}
|
|
||||||
Err(e) => return Err(Error::from(e)),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.lookup_inode(&path)?
|
|
||||||
};
|
|
||||||
let abs_path = self.convert_to_abs_path(&path);
|
|
||||||
Ok(Box::new(INodeFile::open(inode, &abs_path, flags)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lookup INode from the cwd of the process
|
|
||||||
pub fn lookup_inode(&self, path: &str) -> Result<Arc<dyn INode>> {
|
|
||||||
debug!("lookup_inode: cwd: {:?}, path: {:?}", self.get_cwd(), path);
|
|
||||||
if path.len() > 0 && path.as_bytes()[0] == b'/' {
|
|
||||||
// absolute path
|
|
||||||
let abs_path = path.trim_start_matches('/');
|
|
||||||
let inode = ROOT_INODE.lookup(abs_path)?;
|
|
||||||
Ok(inode)
|
|
||||||
} else {
|
|
||||||
// relative path
|
|
||||||
let cwd = self.get_cwd().trim_start_matches('/');
|
|
||||||
let inode = ROOT_INODE.lookup(cwd)?.lookup(path)?;
|
|
||||||
Ok(inode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert the path to be absolute
|
|
||||||
pub fn convert_to_abs_path(&self, path: &str) -> String {
|
|
||||||
debug!(
|
|
||||||
"convert_to_abs_path: cwd: {:?}, path: {:?}",
|
|
||||||
self.get_cwd(),
|
|
||||||
path
|
|
||||||
);
|
|
||||||
if path.len() > 0 && path.as_bytes()[0] == b'/' {
|
|
||||||
// path is absolute path already
|
|
||||||
return path.to_owned();
|
|
||||||
}
|
|
||||||
let cwd = {
|
|
||||||
if !self.get_cwd().ends_with("/") {
|
|
||||||
self.get_cwd().to_owned() + "/"
|
|
||||||
} else {
|
|
||||||
self.get_cwd().to_owned()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
cwd + path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Split a `path` str to `(base_path, file_name)`
|
|
||||||
fn split_path(path: &str) -> (&str, &str) {
|
|
||||||
let mut split = path.trim_end_matches('/').rsplitn(2, '/');
|
|
||||||
let file_name = split.next().unwrap();
|
|
||||||
let mut dir_path = split.next().unwrap_or(".");
|
|
||||||
if dir_path == "" {
|
|
||||||
dir_path = "/";
|
|
||||||
}
|
|
||||||
(dir_path, file_name)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(packed)] // Don't use 'C'. Or its size will align up to 8 bytes.
|
|
||||||
pub struct LinuxDirent64 {
|
|
||||||
/// Inode number
|
|
||||||
ino: u64,
|
|
||||||
/// Offset to next structure
|
|
||||||
offset: u64,
|
|
||||||
/// Size of this dirent
|
|
||||||
reclen: u16,
|
|
||||||
/// File type
|
|
||||||
type_: u8,
|
|
||||||
/// Filename (null-terminated)
|
|
||||||
name: [u8; 0],
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DirentBufWriter<'a> {
|
|
||||||
buf: &'a mut [u8],
|
|
||||||
rest_size: usize,
|
|
||||||
written_size: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> DirentBufWriter<'a> {
|
|
||||||
unsafe fn new(buf: &'a mut [u8]) -> Self {
|
|
||||||
let rest_size = buf.len();
|
|
||||||
DirentBufWriter {
|
|
||||||
buf,
|
|
||||||
rest_size,
|
|
||||||
written_size: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn try_write(&mut self, inode: u64, type_: u8, name: &str) -> Result<()> {
|
|
||||||
let len = ::core::mem::size_of::<LinuxDirent64>() + name.len() + 1;
|
|
||||||
let len = (len + 7) / 8 * 8; // align up
|
|
||||||
if self.rest_size < len {
|
|
||||||
return_errno!(EINVAL, "the given buffer is too small");
|
|
||||||
}
|
|
||||||
let dent = LinuxDirent64 {
|
|
||||||
ino: inode,
|
|
||||||
offset: 0,
|
|
||||||
reclen: len as u16,
|
|
||||||
type_,
|
|
||||||
name: [],
|
|
||||||
};
|
|
||||||
unsafe {
|
|
||||||
let ptr = self.buf.as_mut_ptr().add(self.written_size) as *mut LinuxDirent64;
|
|
||||||
ptr.write(dent);
|
|
||||||
let name_ptr = ptr.add(1) as _;
|
|
||||||
write_cstr(name_ptr, name);
|
|
||||||
}
|
|
||||||
self.rest_size -= len;
|
|
||||||
self.written_size += len;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct Stat {
|
|
||||||
/// ID of device containing file
|
|
||||||
dev: u64,
|
|
||||||
/// inode number
|
|
||||||
ino: u64,
|
|
||||||
/// number of hard links
|
|
||||||
nlink: u64,
|
|
||||||
|
|
||||||
/// file type and mode
|
|
||||||
mode: StatMode,
|
|
||||||
/// user ID of owner
|
|
||||||
uid: u32,
|
|
||||||
/// group ID of owner
|
|
||||||
gid: u32,
|
|
||||||
/// padding
|
|
||||||
_pad0: u32,
|
|
||||||
/// device ID (if special file)
|
|
||||||
rdev: u64,
|
|
||||||
/// total size, in bytes
|
|
||||||
size: u64,
|
|
||||||
/// blocksize for filesystem I/O
|
|
||||||
blksize: u64,
|
|
||||||
/// number of 512B blocks allocated
|
|
||||||
blocks: u64,
|
|
||||||
|
|
||||||
/// last access time
|
|
||||||
atime: Timespec,
|
|
||||||
/// last modification time
|
|
||||||
mtime: Timespec,
|
|
||||||
/// last status change time
|
|
||||||
ctime: Timespec,
|
|
||||||
}
|
|
||||||
|
|
||||||
bitflags! {
|
|
||||||
pub struct StatMode: u32 {
|
|
||||||
const NULL = 0;
|
|
||||||
/// Type
|
|
||||||
const TYPE_MASK = 0o170000;
|
|
||||||
/// FIFO
|
|
||||||
const FIFO = 0o010000;
|
|
||||||
/// character device
|
|
||||||
const CHAR = 0o020000;
|
|
||||||
/// directory
|
|
||||||
const DIR = 0o040000;
|
|
||||||
/// block device
|
|
||||||
const BLOCK = 0o060000;
|
|
||||||
/// ordinary regular file
|
|
||||||
const FILE = 0o100000;
|
|
||||||
/// symbolic link
|
|
||||||
const LINK = 0o120000;
|
|
||||||
/// socket
|
|
||||||
const SOCKET = 0o140000;
|
|
||||||
|
|
||||||
/// Set-user-ID on execution.
|
|
||||||
const SET_UID = 0o4000;
|
|
||||||
/// Set-group-ID on execution.
|
|
||||||
const SET_GID = 0o2000;
|
|
||||||
|
|
||||||
/// Read, write, execute/search by owner.
|
|
||||||
const OWNER_MASK = 0o700;
|
|
||||||
/// Read permission, owner.
|
|
||||||
const OWNER_READ = 0o400;
|
|
||||||
/// Write permission, owner.
|
|
||||||
const OWNER_WRITE = 0o200;
|
|
||||||
/// Execute/search permission, owner.
|
|
||||||
const OWNER_EXEC = 0o100;
|
|
||||||
|
|
||||||
/// Read, write, execute/search by group.
|
|
||||||
const GROUP_MASK = 0o70;
|
|
||||||
/// Read permission, group.
|
|
||||||
const GROUP_READ = 0o40;
|
|
||||||
/// Write permission, group.
|
|
||||||
const GROUP_WRITE = 0o20;
|
|
||||||
/// Execute/search permission, group.
|
|
||||||
const GROUP_EXEC = 0o10;
|
|
||||||
|
|
||||||
/// Read, write, execute/search by others.
|
|
||||||
const OTHER_MASK = 0o7;
|
|
||||||
/// Read permission, others.
|
|
||||||
const OTHER_READ = 0o4;
|
|
||||||
/// Write permission, others.
|
|
||||||
const OTHER_WRITE = 0o2;
|
|
||||||
/// Execute/search permission, others.
|
|
||||||
const OTHER_EXEC = 0o1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StatMode {
|
|
||||||
fn from_type_mode(type_: FileType, mode: u16) -> Self {
|
|
||||||
let type_ = match type_ {
|
|
||||||
FileType::File => StatMode::FILE,
|
|
||||||
FileType::Dir => StatMode::DIR,
|
|
||||||
FileType::SymLink => StatMode::LINK,
|
|
||||||
FileType::CharDevice => StatMode::CHAR,
|
|
||||||
FileType::BlockDevice => StatMode::BLOCK,
|
|
||||||
FileType::Socket => StatMode::SOCKET,
|
|
||||||
FileType::NamedPipe => StatMode::FIFO,
|
|
||||||
_ => StatMode::NULL,
|
|
||||||
};
|
|
||||||
let mode = StatMode::from_bits_truncate(mode as u32);
|
|
||||||
type_ | mode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Metadata> for Stat {
|
|
||||||
fn from(info: Metadata) -> Self {
|
|
||||||
Stat {
|
|
||||||
dev: info.dev as u64,
|
|
||||||
ino: info.inode as u64,
|
|
||||||
mode: StatMode::from_type_mode(info.type_, info.mode as u16),
|
|
||||||
nlink: info.nlinks as u64,
|
|
||||||
uid: info.uid as u32,
|
|
||||||
gid: info.gid as u32,
|
|
||||||
rdev: 0,
|
|
||||||
size: info.size as u64,
|
|
||||||
blksize: info.blk_size as u64,
|
|
||||||
blocks: info.blocks as u64,
|
|
||||||
atime: info.atime,
|
|
||||||
mtime: info.mtime,
|
|
||||||
ctime: info.ctime,
|
|
||||||
_pad0: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write a Rust string to C string
|
|
||||||
pub unsafe fn write_cstr(ptr: *mut u8, s: &str) {
|
|
||||||
ptr.copy_from(s.as_ptr(), s.len());
|
|
||||||
ptr.add(s.len()).write(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result<isize> {
|
|
||||||
info!("fcntl: fd: {:?}, cmd: {:?}", &fd, cmd);
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let mut current = current_ref.lock().unwrap();
|
|
||||||
let file_table_ref = current.get_files();
|
|
||||||
let ret = fcntl::do_fcntl(file_table_ref, fd, cmd)?;
|
|
||||||
Ok(ret)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn do_readlink(path: &str, buf: &mut [u8]) -> Result<usize> {
|
|
||||||
info!("readlink: path: {:?}", path);
|
|
||||||
let file_path = {
|
|
||||||
if path == "/proc/self/exe" {
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current = current_ref.lock().unwrap();
|
|
||||||
current.get_elf_path().to_owned()
|
|
||||||
} else if path.starts_with("/proc/self/fd") {
|
|
||||||
let fd = path
|
|
||||||
.trim_start_matches("/proc/self/fd/")
|
|
||||||
.parse::<FileDesc>()
|
|
||||||
.map_err(|e| errno!(EBADF, "Invalid file descriptor"))?;
|
|
||||||
let current_ref = process::get_current();
|
|
||||||
let current = current_ref.lock().unwrap();
|
|
||||||
let file_ref = current.get_files().lock().unwrap().get(fd)?;
|
|
||||||
if let Ok(inode_file) = file_ref.as_inode_file() {
|
|
||||||
inode_file.get_abs_path().to_owned()
|
|
||||||
} else {
|
|
||||||
// TODO: support special device files
|
|
||||||
return_errno!(EINVAL, "not a normal file link")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TODO: support symbolic links
|
|
||||||
return_errno!(EINVAL, "not a symbolic link")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let len = file_path.len().min(buf.len());
|
|
||||||
buf[0..len].copy_from_slice(&file_path.as_bytes()[0..len]);
|
|
||||||
Ok(len)
|
|
||||||
}
|
|
||||||
|
@ -154,3 +154,19 @@ impl File for PipeWriter {
|
|||||||
|
|
||||||
unsafe impl Send for PipeWriter {}
|
unsafe impl Send for PipeWriter {}
|
||||||
unsafe impl Sync for PipeWriter {}
|
unsafe impl Sync for PipeWriter {}
|
||||||
|
|
||||||
|
pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2]> {
|
||||||
|
info!("pipe2: flags: {:#x}", flags);
|
||||||
|
let creation_flags = CreationFlags::from_bits_truncate(flags);
|
||||||
|
let current_ref = process::get_current();
|
||||||
|
let current = current_ref.lock().unwrap();
|
||||||
|
let pipe = Pipe::new(StatusFlags::from_bits_truncate(flags))?;
|
||||||
|
|
||||||
|
let file_table_ref = current.get_files();
|
||||||
|
let mut file_table = file_table_ref.lock().unwrap();
|
||||||
|
let close_on_spawn = creation_flags.must_close_on_spawn();
|
||||||
|
let reader_fd = file_table.put(Arc::new(Box::new(pipe.reader)), close_on_spawn);
|
||||||
|
let writer_fd = file_table.put(Arc::new(Box::new(pipe.writer)), close_on_spawn);
|
||||||
|
info!("pipe2: reader_fd: {}, writer_fd: {}", reader_fd, writer_fd);
|
||||||
|
Ok([reader_fd, writer_fd])
|
||||||
|
}
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
use super::hostfs::HostFS;
|
use super::hostfs::HostFS;
|
||||||
use super::sgx_impl::{SgxStorage, SgxUuidProvider};
|
use super::sefs::{SgxStorage, SgxUuidProvider};
|
||||||
use super::*;
|
use super::*;
|
||||||
use config::{ConfigMount, ConfigMountFsType};
|
use config::{ConfigMount, ConfigMountFsType};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use rcore_fs::vfs::{FileSystem, FileType, FsError, INode};
|
|
||||||
use rcore_fs_mountfs::{MNode, MountFS};
|
use rcore_fs_mountfs::{MNode, MountFS};
|
||||||
use rcore_fs_ramfs::RamFS;
|
use rcore_fs_ramfs::RamFS;
|
||||||
use rcore_fs_sefs::dev::*;
|
use rcore_fs_sefs::dev::*;
|
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 super::*;
|
||||||
use alloc::string::ToString;
|
use rcore_fs_sefs::dev::{DevResult, DeviceError, File, SefsMac, Storage};
|
||||||
use rcore_fs::dev::TimeProvider;
|
|
||||||
use rcore_fs::vfs::Timespec;
|
|
||||||
use rcore_fs_sefs::dev::*;
|
|
||||||
use sgx_trts::libc;
|
|
||||||
use sgx_types::*;
|
|
||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
use std::io::{Read, Seek, SeekFrom, Write};
|
use std::io::{Read, Seek, SeekFrom, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sgxfs::{remove, OpenOptions, SgxFile};
|
use std::sgxfs::{remove, OpenOptions, SgxFile};
|
||||||
use std::string::String;
|
|
||||||
use std::sync::{Arc, SgxMutex as Mutex};
|
use std::sync::{Arc, SgxMutex as Mutex};
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
|
||||||
|
|
||||||
use std::collections::hash_map::DefaultHasher;
|
|
||||||
use std::hash::{Hash, Hasher};
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
fn sgx_read_rand(rand_buf: *mut u8, buf_size: usize) -> sgx_status_t;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SgxUuidProvider;
|
|
||||||
|
|
||||||
impl UuidProvider for SgxUuidProvider {
|
|
||||||
fn generate_uuid(&self) -> SefsUuid {
|
|
||||||
let mut uuid: [u8; 16] = [0u8; 16];
|
|
||||||
let buf = uuid.as_mut_ptr();
|
|
||||||
let size = 16;
|
|
||||||
let status = unsafe { sgx_read_rand(buf, size) };
|
|
||||||
assert!(status == sgx_status_t::SGX_SUCCESS);
|
|
||||||
SefsUuid(uuid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct SgxStorage {
|
pub struct SgxStorage {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
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 super::*;
|
||||||
|
use fs::{File, FileDesc, FileRef};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::btree_map::BTreeMap;
|
use std::collections::btree_map::BTreeMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
@ -1,14 +1,17 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use std::*;
|
use std;
|
||||||
|
|
||||||
|
mod io_multiplexing;
|
||||||
mod iovs;
|
mod iovs;
|
||||||
mod msg;
|
mod msg;
|
||||||
mod msg_flags;
|
mod msg_flags;
|
||||||
mod socket_file;
|
mod socket_file;
|
||||||
mod syscalls;
|
mod syscalls;
|
||||||
|
mod unix_socket;
|
||||||
|
|
||||||
pub use self::iovs::{Iovs, IovsMut, SliceAsLibcIovec};
|
pub use self::iovs::{Iovs, IovsMut, SliceAsLibcIovec};
|
||||||
pub use self::msg::{msghdr, msghdr_mut, MsgHdr, MsgHdrMut};
|
pub use self::msg::{msghdr, msghdr_mut, MsgHdr, MsgHdrMut};
|
||||||
pub use self::msg_flags::MsgFlags;
|
pub use self::msg_flags::MsgFlags;
|
||||||
pub use self::socket_file::{AsSocket, SocketFile};
|
pub use self::socket_file::{AsSocket, SocketFile};
|
||||||
pub use self::syscalls::{do_recvmsg, do_sendmsg};
|
pub use self::syscalls::*;
|
||||||
|
pub use self::unix_socket::{AsUnixSocket, UnixSocketFile};
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use fs::{AsUnixSocket, File, FileDesc, FileRef, UnixSocketFile};
|
use super::io_multiplexing;
|
||||||
|
use fs::{File, FileDesc, FileRef};
|
||||||
use process::Process;
|
use process::Process;
|
||||||
use util::mem_util::from_user;
|
use util::mem_util::from_user;
|
||||||
|
|
||||||
@ -124,3 +125,114 @@ impl c_msghdr_ext for msghdr_mut {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn do_select(
|
||||||
|
nfds: c_int,
|
||||||
|
readfds: *mut libc::fd_set,
|
||||||
|
writefds: *mut libc::fd_set,
|
||||||
|
exceptfds: *mut libc::fd_set,
|
||||||
|
timeout: *const libc::timeval,
|
||||||
|
) -> Result<isize> {
|
||||||
|
// check arguments
|
||||||
|
if nfds < 0 || nfds >= libc::FD_SETSIZE as c_int {
|
||||||
|
return_errno!(EINVAL, "nfds is negative or exceeds the resource limit");
|
||||||
|
}
|
||||||
|
let nfds = nfds as usize;
|
||||||
|
|
||||||
|
let mut zero_fds0: libc::fd_set = unsafe { core::mem::zeroed() };
|
||||||
|
let mut zero_fds1: libc::fd_set = unsafe { core::mem::zeroed() };
|
||||||
|
let mut zero_fds2: libc::fd_set = unsafe { core::mem::zeroed() };
|
||||||
|
|
||||||
|
let readfds = if !readfds.is_null() {
|
||||||
|
from_user::check_mut_ptr(readfds)?;
|
||||||
|
unsafe { &mut *readfds }
|
||||||
|
} else {
|
||||||
|
&mut zero_fds0
|
||||||
|
};
|
||||||
|
let writefds = if !writefds.is_null() {
|
||||||
|
from_user::check_mut_ptr(writefds)?;
|
||||||
|
unsafe { &mut *writefds }
|
||||||
|
} else {
|
||||||
|
&mut zero_fds1
|
||||||
|
};
|
||||||
|
let exceptfds = if !exceptfds.is_null() {
|
||||||
|
from_user::check_mut_ptr(exceptfds)?;
|
||||||
|
unsafe { &mut *exceptfds }
|
||||||
|
} else {
|
||||||
|
&mut zero_fds2
|
||||||
|
};
|
||||||
|
let timeout = if !timeout.is_null() {
|
||||||
|
from_user::check_ptr(timeout)?;
|
||||||
|
Some(unsafe { timeout.read() })
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let n = io_multiplexing::do_select(nfds, readfds, writefds, exceptfds, timeout)?;
|
||||||
|
Ok(n as isize)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_poll(fds: *mut libc::pollfd, nfds: libc::nfds_t, timeout: c_int) -> Result<isize> {
|
||||||
|
from_user::check_mut_array(fds, nfds as usize)?;
|
||||||
|
let polls = unsafe { std::slice::from_raw_parts_mut(fds, nfds as usize) };
|
||||||
|
|
||||||
|
let n = io_multiplexing::do_poll(polls, timeout)?;
|
||||||
|
Ok(n as isize)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_epoll_create(size: c_int) -> Result<isize> {
|
||||||
|
if size <= 0 {
|
||||||
|
return_errno!(EINVAL, "size is not positive");
|
||||||
|
}
|
||||||
|
do_epoll_create1(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_epoll_create1(flags: c_int) -> Result<isize> {
|
||||||
|
let fd = io_multiplexing::do_epoll_create1(flags)?;
|
||||||
|
Ok(fd as isize)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_epoll_ctl(
|
||||||
|
epfd: c_int,
|
||||||
|
op: c_int,
|
||||||
|
fd: c_int,
|
||||||
|
event: *const libc::epoll_event,
|
||||||
|
) -> Result<isize> {
|
||||||
|
if !event.is_null() {
|
||||||
|
from_user::check_ptr(event)?;
|
||||||
|
}
|
||||||
|
io_multiplexing::do_epoll_ctl(epfd as FileDesc, op, fd as FileDesc, event)?;
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_epoll_wait(
|
||||||
|
epfd: c_int,
|
||||||
|
events: *mut libc::epoll_event,
|
||||||
|
maxevents: c_int,
|
||||||
|
timeout: c_int,
|
||||||
|
) -> Result<isize> {
|
||||||
|
let maxevents = {
|
||||||
|
if maxevents <= 0 {
|
||||||
|
return_errno!(EINVAL, "maxevents <= 0");
|
||||||
|
}
|
||||||
|
maxevents as usize
|
||||||
|
};
|
||||||
|
let events = {
|
||||||
|
from_user::check_mut_array(events, maxevents)?;
|
||||||
|
unsafe { std::slice::from_raw_parts_mut(events, maxevents) }
|
||||||
|
};
|
||||||
|
let count = io_multiplexing::do_epoll_wait(epfd as FileDesc, events, timeout)?;
|
||||||
|
Ok(count as isize)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn do_epoll_pwait(
|
||||||
|
epfd: c_int,
|
||||||
|
events: *mut libc::epoll_event,
|
||||||
|
maxevents: c_int,
|
||||||
|
timeout: c_int,
|
||||||
|
sigmask: *const usize, //TODO:add sigset_t
|
||||||
|
) -> Result<isize> {
|
||||||
|
info!("epoll_pwait");
|
||||||
|
//TODO:add signal support
|
||||||
|
do_epoll_wait(epfd, events, maxevents, 0)
|
||||||
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use super::*;
|
use super::*;
|
||||||
use alloc::string::ToString;
|
use fs::{File, FileRef, IoctlCmd};
|
||||||
|
use rcore_fs::vfs::{FileType, Metadata, Timespec};
|
||||||
|
use std::any::Any;
|
||||||
use std::collections::btree_map::BTreeMap;
|
use std::collections::btree_map::BTreeMap;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering};
|
use std::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering};
|
@ -7,12 +7,9 @@
|
|||||||
//! 3. Dispatch the syscall to `do_*` (at this file)
|
//! 3. Dispatch the syscall to `do_*` (at this file)
|
||||||
//! 4. Do some memory checks then call `mod::do_*` (at each module)
|
//! 4. Do some memory checks then call `mod::do_*` (at each module)
|
||||||
|
|
||||||
use fs::{
|
use fs::{File, FileDesc, FileRef, Stat};
|
||||||
AccessFlags, AccessModes, AsUnixSocket, FcntlCmd, File, FileDesc, FileRef, IoctlCmd,
|
|
||||||
UnixSocketFile, AT_FDCWD,
|
|
||||||
};
|
|
||||||
use misc::{resource_t, rlimit_t, utsname_t};
|
use misc::{resource_t, rlimit_t, utsname_t};
|
||||||
use net::{msghdr, msghdr_mut, AsSocket, SocketFile};
|
use net::{msghdr, msghdr_mut, AsSocket, AsUnixSocket, SocketFile, UnixSocketFile};
|
||||||
use process::{pid_t, ChildProcessFilter, CloneFlags, CpuSet, FileAction, FutexFlags, FutexOp};
|
use process::{pid_t, ChildProcessFilter, CloneFlags, CpuSet, FileAction, FutexFlags, FutexOp};
|
||||||
use std::ffi::{CStr, CString};
|
use std::ffi::{CStr, CString};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
@ -72,81 +69,81 @@ pub extern "C" fn dispatch_syscall(
|
|||||||
|
|
||||||
let ret = match num {
|
let ret = match num {
|
||||||
// file
|
// file
|
||||||
SYS_OPEN => do_open(arg0 as *const i8, arg1 as u32, arg2 as u32),
|
SYS_OPEN => fs::do_open(arg0 as *const i8, arg1 as u32, arg2 as u32),
|
||||||
SYS_CLOSE => do_close(arg0 as FileDesc),
|
SYS_CLOSE => fs::do_close(arg0 as FileDesc),
|
||||||
SYS_READ => do_read(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize),
|
SYS_READ => fs::do_read(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize),
|
||||||
SYS_WRITE => do_write(arg0 as FileDesc, arg1 as *const u8, arg2 as usize),
|
SYS_WRITE => fs::do_write(arg0 as FileDesc, arg1 as *const u8, arg2 as usize),
|
||||||
SYS_PREAD64 => do_pread(
|
SYS_PREAD64 => fs::do_pread(
|
||||||
arg0 as FileDesc,
|
arg0 as FileDesc,
|
||||||
arg1 as *mut u8,
|
arg1 as *mut u8,
|
||||||
arg2 as usize,
|
arg2 as usize,
|
||||||
arg3 as usize,
|
arg3 as usize,
|
||||||
),
|
),
|
||||||
SYS_PWRITE64 => do_pwrite(
|
SYS_PWRITE64 => fs::do_pwrite(
|
||||||
arg0 as FileDesc,
|
arg0 as FileDesc,
|
||||||
arg1 as *const u8,
|
arg1 as *const u8,
|
||||||
arg2 as usize,
|
arg2 as usize,
|
||||||
arg3 as usize,
|
arg3 as usize,
|
||||||
),
|
),
|
||||||
SYS_READV => do_readv(arg0 as FileDesc, arg1 as *mut iovec_t, arg2 as i32),
|
SYS_READV => fs::do_readv(arg0 as FileDesc, arg1 as *mut fs::iovec_t, arg2 as i32),
|
||||||
SYS_WRITEV => do_writev(arg0 as FileDesc, arg1 as *mut iovec_t, arg2 as i32),
|
SYS_WRITEV => fs::do_writev(arg0 as FileDesc, arg1 as *mut fs::iovec_t, arg2 as i32),
|
||||||
SYS_STAT => do_stat(arg0 as *const i8, arg1 as *mut fs::Stat),
|
SYS_STAT => fs::do_stat(arg0 as *const i8, arg1 as *mut Stat),
|
||||||
SYS_FSTAT => do_fstat(arg0 as FileDesc, arg1 as *mut fs::Stat),
|
SYS_FSTAT => fs::do_fstat(arg0 as FileDesc, arg1 as *mut Stat),
|
||||||
SYS_LSTAT => do_lstat(arg0 as *const i8, arg1 as *mut fs::Stat),
|
SYS_LSTAT => fs::do_lstat(arg0 as *const i8, arg1 as *mut Stat),
|
||||||
SYS_ACCESS => do_access(arg0 as *const i8, arg1 as u32),
|
SYS_ACCESS => fs::do_access(arg0 as *const i8, arg1 as u32),
|
||||||
SYS_FACCESSAT => do_faccessat(arg0 as i32, arg1 as *const i8, arg2 as u32, arg3 as u32),
|
SYS_FACCESSAT => fs::do_faccessat(arg0 as i32, arg1 as *const i8, arg2 as u32, arg3 as u32),
|
||||||
SYS_LSEEK => do_lseek(arg0 as FileDesc, arg1 as off_t, arg2 as i32),
|
SYS_LSEEK => fs::do_lseek(arg0 as FileDesc, arg1 as off_t, arg2 as i32),
|
||||||
SYS_FSYNC => do_fsync(arg0 as FileDesc),
|
SYS_FSYNC => fs::do_fsync(arg0 as FileDesc),
|
||||||
SYS_FDATASYNC => do_fdatasync(arg0 as FileDesc),
|
SYS_FDATASYNC => fs::do_fdatasync(arg0 as FileDesc),
|
||||||
SYS_TRUNCATE => do_truncate(arg0 as *const i8, arg1 as usize),
|
SYS_TRUNCATE => fs::do_truncate(arg0 as *const i8, arg1 as usize),
|
||||||
SYS_FTRUNCATE => do_ftruncate(arg0 as FileDesc, arg1 as usize),
|
SYS_FTRUNCATE => fs::do_ftruncate(arg0 as FileDesc, arg1 as usize),
|
||||||
SYS_GETDENTS64 => do_getdents64(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize),
|
SYS_GETDENTS64 => fs::do_getdents64(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize),
|
||||||
SYS_SYNC => do_sync(),
|
SYS_SYNC => fs::do_sync(),
|
||||||
SYS_GETCWD => do_getcwd(arg0 as *mut u8, arg1 as usize),
|
SYS_GETCWD => do_getcwd(arg0 as *mut u8, arg1 as usize),
|
||||||
SYS_CHDIR => do_chdir(arg0 as *mut i8),
|
SYS_CHDIR => fs::do_chdir(arg0 as *mut i8),
|
||||||
SYS_RENAME => do_rename(arg0 as *const i8, arg1 as *const i8),
|
SYS_RENAME => fs::do_rename(arg0 as *const i8, arg1 as *const i8),
|
||||||
SYS_MKDIR => do_mkdir(arg0 as *const i8, arg1 as usize),
|
SYS_MKDIR => fs::do_mkdir(arg0 as *const i8, arg1 as usize),
|
||||||
SYS_RMDIR => do_rmdir(arg0 as *const i8),
|
SYS_RMDIR => fs::do_rmdir(arg0 as *const i8),
|
||||||
SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8),
|
SYS_LINK => fs::do_link(arg0 as *const i8, arg1 as *const i8),
|
||||||
SYS_UNLINK => do_unlink(arg0 as *const i8),
|
SYS_UNLINK => fs::do_unlink(arg0 as *const i8),
|
||||||
SYS_READLINK => do_readlink(arg0 as *const i8, arg1 as *mut u8, arg2 as usize),
|
SYS_READLINK => fs::do_readlink(arg0 as *const i8, arg1 as *mut u8, arg2 as usize),
|
||||||
SYS_SENDFILE => do_sendfile(
|
SYS_SENDFILE => fs::do_sendfile(
|
||||||
arg0 as FileDesc,
|
arg0 as FileDesc,
|
||||||
arg1 as FileDesc,
|
arg1 as FileDesc,
|
||||||
arg2 as *mut off_t,
|
arg2 as *mut off_t,
|
||||||
arg3 as usize,
|
arg3 as usize,
|
||||||
),
|
),
|
||||||
SYS_FCNTL => do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64),
|
SYS_FCNTL => fs::do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64),
|
||||||
SYS_IOCTL => do_ioctl(arg0 as FileDesc, arg1 as u32, arg2 as *mut u8),
|
SYS_IOCTL => fs::do_ioctl(arg0 as FileDesc, arg1 as u32, arg2 as *mut u8),
|
||||||
|
|
||||||
// IO multiplexing
|
// IO multiplexing
|
||||||
SYS_SELECT => do_select(
|
SYS_SELECT => net::do_select(
|
||||||
arg0 as c_int,
|
arg0 as c_int,
|
||||||
arg1 as *mut libc::fd_set,
|
arg1 as *mut libc::fd_set,
|
||||||
arg2 as *mut libc::fd_set,
|
arg2 as *mut libc::fd_set,
|
||||||
arg3 as *mut libc::fd_set,
|
arg3 as *mut libc::fd_set,
|
||||||
arg4 as *const libc::timeval,
|
arg4 as *const libc::timeval,
|
||||||
),
|
),
|
||||||
SYS_POLL => do_poll(
|
SYS_POLL => net::do_poll(
|
||||||
arg0 as *mut libc::pollfd,
|
arg0 as *mut libc::pollfd,
|
||||||
arg1 as libc::nfds_t,
|
arg1 as libc::nfds_t,
|
||||||
arg2 as c_int,
|
arg2 as c_int,
|
||||||
),
|
),
|
||||||
SYS_EPOLL_CREATE => do_epoll_create(arg0 as c_int),
|
SYS_EPOLL_CREATE => net::do_epoll_create(arg0 as c_int),
|
||||||
SYS_EPOLL_CREATE1 => do_epoll_create1(arg0 as c_int),
|
SYS_EPOLL_CREATE1 => net::do_epoll_create1(arg0 as c_int),
|
||||||
SYS_EPOLL_CTL => do_epoll_ctl(
|
SYS_EPOLL_CTL => net::do_epoll_ctl(
|
||||||
arg0 as c_int,
|
arg0 as c_int,
|
||||||
arg1 as c_int,
|
arg1 as c_int,
|
||||||
arg2 as c_int,
|
arg2 as c_int,
|
||||||
arg3 as *const libc::epoll_event,
|
arg3 as *const libc::epoll_event,
|
||||||
),
|
),
|
||||||
SYS_EPOLL_WAIT => do_epoll_wait(
|
SYS_EPOLL_WAIT => net::do_epoll_wait(
|
||||||
arg0 as c_int,
|
arg0 as c_int,
|
||||||
arg1 as *mut libc::epoll_event,
|
arg1 as *mut libc::epoll_event,
|
||||||
arg2 as c_int,
|
arg2 as c_int,
|
||||||
arg3 as c_int,
|
arg3 as c_int,
|
||||||
),
|
),
|
||||||
SYS_EPOLL_PWAIT => do_epoll_pwait(
|
SYS_EPOLL_PWAIT => net::do_epoll_pwait(
|
||||||
arg0 as c_int,
|
arg0 as c_int,
|
||||||
arg1 as *mut libc::epoll_event,
|
arg1 as *mut libc::epoll_event,
|
||||||
arg2 as c_int,
|
arg2 as c_int,
|
||||||
@ -225,11 +222,11 @@ pub extern "C" fn dispatch_syscall(
|
|||||||
SYS_MPROTECT => do_mprotect(arg0 as usize, arg1 as usize, arg2 as u32),
|
SYS_MPROTECT => do_mprotect(arg0 as usize, arg1 as usize, arg2 as u32),
|
||||||
SYS_BRK => do_brk(arg0 as usize),
|
SYS_BRK => do_brk(arg0 as usize),
|
||||||
|
|
||||||
SYS_PIPE => do_pipe2(arg0 as *mut i32, 0),
|
SYS_PIPE => fs::do_pipe2(arg0 as *mut i32, 0),
|
||||||
SYS_PIPE2 => do_pipe2(arg0 as *mut i32, arg1 as u32),
|
SYS_PIPE2 => fs::do_pipe2(arg0 as *mut i32, arg1 as u32),
|
||||||
SYS_DUP => do_dup(arg0 as FileDesc),
|
SYS_DUP => fs::do_dup(arg0 as FileDesc),
|
||||||
SYS_DUP2 => do_dup2(arg0 as FileDesc, arg1 as FileDesc),
|
SYS_DUP2 => fs::do_dup2(arg0 as FileDesc, arg1 as FileDesc),
|
||||||
SYS_DUP3 => do_dup3(arg0 as FileDesc, arg1 as FileDesc, arg2 as u32),
|
SYS_DUP3 => fs::do_dup3(arg0 as FileDesc, arg1 as FileDesc, arg2 as u32),
|
||||||
|
|
||||||
SYS_GETTIMEOFDAY => do_gettimeofday(arg0 as *mut timeval_t),
|
SYS_GETTIMEOFDAY => do_gettimeofday(arg0 as *mut timeval_t),
|
||||||
SYS_CLOCK_GETTIME => do_clock_gettime(arg0 as clockid_t, arg1 as *mut timespec_t),
|
SYS_CLOCK_GETTIME => do_clock_gettime(arg0 as clockid_t, arg1 as *mut timespec_t),
|
||||||
@ -362,12 +359,6 @@ fn print_syscall_timing() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
|
||||||
pub struct iovec_t {
|
|
||||||
base: *const c_void,
|
|
||||||
len: size_t,
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This Rust-version of fdop correspond to the C-version one in Occlum.
|
* This Rust-version of fdop correspond to the C-version one in Occlum.
|
||||||
* See <path_to_musl_libc>/src/process/fdop.h.
|
* See <path_to_musl_libc>/src/process/fdop.h.
|
||||||
@ -518,196 +509,6 @@ pub fn do_futex(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_open(path: *const i8, flags: u32, mode: u32) -> Result<isize> {
|
|
||||||
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
|
||||||
let fd = fs::do_open(&path, flags, mode)?;
|
|
||||||
Ok(fd as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_close(fd: FileDesc) -> Result<isize> {
|
|
||||||
fs::do_close(fd)?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_read(fd: FileDesc, buf: *mut u8, size: usize) -> Result<isize> {
|
|
||||||
let safe_buf = {
|
|
||||||
check_mut_array(buf, size)?;
|
|
||||||
unsafe { std::slice::from_raw_parts_mut(buf, size) }
|
|
||||||
};
|
|
||||||
let len = fs::do_read(fd, safe_buf)?;
|
|
||||||
Ok(len as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_write(fd: FileDesc, buf: *const u8, size: usize) -> Result<isize> {
|
|
||||||
let safe_buf = {
|
|
||||||
check_array(buf, size)?;
|
|
||||||
unsafe { std::slice::from_raw_parts(buf, size) }
|
|
||||||
};
|
|
||||||
let len = fs::do_write(fd, safe_buf)?;
|
|
||||||
Ok(len as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_writev(fd: FileDesc, iov: *const iovec_t, count: i32) -> Result<isize> {
|
|
||||||
let count = {
|
|
||||||
if count < 0 {
|
|
||||||
return_errno!(EINVAL, "Invalid count of iovec");
|
|
||||||
}
|
|
||||||
count as usize
|
|
||||||
};
|
|
||||||
|
|
||||||
check_array(iov, count);
|
|
||||||
let bufs_vec = {
|
|
||||||
let mut bufs_vec = Vec::with_capacity(count);
|
|
||||||
for iov_i in 0..count {
|
|
||||||
let iov_ptr = unsafe { iov.offset(iov_i as isize) };
|
|
||||||
let iov = unsafe { &*iov_ptr };
|
|
||||||
let buf = unsafe { std::slice::from_raw_parts(iov.base as *const u8, iov.len) };
|
|
||||||
bufs_vec.push(buf);
|
|
||||||
}
|
|
||||||
bufs_vec
|
|
||||||
};
|
|
||||||
let bufs = &bufs_vec[..];
|
|
||||||
|
|
||||||
let len = fs::do_writev(fd, bufs)?;
|
|
||||||
Ok(len as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_readv(fd: FileDesc, iov: *mut iovec_t, count: i32) -> Result<isize> {
|
|
||||||
let count = {
|
|
||||||
if count < 0 {
|
|
||||||
return_errno!(EINVAL, "Invalid count of iovec");
|
|
||||||
}
|
|
||||||
count as usize
|
|
||||||
};
|
|
||||||
|
|
||||||
check_array(iov, count);
|
|
||||||
let mut bufs_vec = {
|
|
||||||
let mut bufs_vec = Vec::with_capacity(count);
|
|
||||||
for iov_i in 0..count {
|
|
||||||
let iov_ptr = unsafe { iov.offset(iov_i as isize) };
|
|
||||||
let iov = unsafe { &*iov_ptr };
|
|
||||||
let buf = unsafe { std::slice::from_raw_parts_mut(iov.base as *mut u8, iov.len) };
|
|
||||||
bufs_vec.push(buf);
|
|
||||||
}
|
|
||||||
bufs_vec
|
|
||||||
};
|
|
||||||
let bufs = &mut bufs_vec[..];
|
|
||||||
|
|
||||||
let len = fs::do_readv(fd, bufs)?;
|
|
||||||
Ok(len as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_pread(fd: FileDesc, buf: *mut u8, size: usize, offset: usize) -> Result<isize> {
|
|
||||||
let safe_buf = {
|
|
||||||
check_mut_array(buf, size)?;
|
|
||||||
unsafe { std::slice::from_raw_parts_mut(buf, size) }
|
|
||||||
};
|
|
||||||
let len = fs::do_pread(fd, safe_buf, offset)?;
|
|
||||||
Ok(len as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_pwrite(fd: FileDesc, buf: *const u8, size: usize, offset: usize) -> Result<isize> {
|
|
||||||
let safe_buf = {
|
|
||||||
check_array(buf, size)?;
|
|
||||||
unsafe { std::slice::from_raw_parts(buf, size) }
|
|
||||||
};
|
|
||||||
let len = fs::do_pwrite(fd, safe_buf, offset)?;
|
|
||||||
Ok(len as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_stat(path: *const i8, stat_buf: *mut fs::Stat) -> Result<isize> {
|
|
||||||
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
|
||||||
check_mut_ptr(stat_buf)?;
|
|
||||||
|
|
||||||
let stat = fs::do_stat(&path)?;
|
|
||||||
unsafe {
|
|
||||||
stat_buf.write(stat);
|
|
||||||
}
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_fstat(fd: FileDesc, stat_buf: *mut fs::Stat) -> Result<isize> {
|
|
||||||
check_mut_ptr(stat_buf)?;
|
|
||||||
|
|
||||||
let stat = fs::do_fstat(fd)?;
|
|
||||||
unsafe {
|
|
||||||
stat_buf.write(stat);
|
|
||||||
}
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_lstat(path: *const i8, stat_buf: *mut fs::Stat) -> Result<isize> {
|
|
||||||
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
|
||||||
check_mut_ptr(stat_buf)?;
|
|
||||||
|
|
||||||
let stat = fs::do_lstat(&path)?;
|
|
||||||
unsafe {
|
|
||||||
stat_buf.write(stat);
|
|
||||||
}
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_lseek(fd: FileDesc, offset: off_t, whence: i32) -> Result<isize> {
|
|
||||||
let seek_from = match whence {
|
|
||||||
0 => {
|
|
||||||
// SEEK_SET
|
|
||||||
if offset < 0 {
|
|
||||||
return_errno!(EINVAL, "Invalid offset");
|
|
||||||
}
|
|
||||||
SeekFrom::Start(offset as u64)
|
|
||||||
}
|
|
||||||
1 => {
|
|
||||||
// SEEK_CUR
|
|
||||||
SeekFrom::Current(offset)
|
|
||||||
}
|
|
||||||
2 => {
|
|
||||||
// SEEK_END
|
|
||||||
SeekFrom::End(offset)
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
return_errno!(EINVAL, "Invalid whence");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let offset = fs::do_lseek(fd, seek_from)?;
|
|
||||||
Ok(offset as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_fsync(fd: FileDesc) -> Result<isize> {
|
|
||||||
fs::do_fsync(fd)?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_fdatasync(fd: FileDesc) -> Result<isize> {
|
|
||||||
fs::do_fdatasync(fd)?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_truncate(path: *const i8, len: usize) -> Result<isize> {
|
|
||||||
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
|
||||||
fs::do_truncate(&path, len)?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_ftruncate(fd: FileDesc, len: usize) -> Result<isize> {
|
|
||||||
fs::do_ftruncate(fd, len)?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_getdents64(fd: FileDesc, buf: *mut u8, buf_size: usize) -> Result<isize> {
|
|
||||||
let safe_buf = {
|
|
||||||
check_mut_array(buf, buf_size)?;
|
|
||||||
unsafe { std::slice::from_raw_parts_mut(buf, buf_size) }
|
|
||||||
};
|
|
||||||
let len = fs::do_getdents64(fd, safe_buf)?;
|
|
||||||
Ok(len as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_sync() -> Result<isize> {
|
|
||||||
fs::do_sync()?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_mmap(
|
fn do_mmap(
|
||||||
addr: usize,
|
addr: usize,
|
||||||
size: usize,
|
size: usize,
|
||||||
@ -817,32 +618,6 @@ fn do_getegid() -> Result<isize> {
|
|||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_pipe2(fds_u: *mut i32, flags: u32) -> Result<isize> {
|
|
||||||
check_mut_array(fds_u, 2)?;
|
|
||||||
// TODO: how to deal with open flags???
|
|
||||||
let fds = fs::do_pipe2(flags as u32)?;
|
|
||||||
unsafe {
|
|
||||||
*fds_u.offset(0) = fds[0] as c_int;
|
|
||||||
*fds_u.offset(1) = fds[1] as c_int;
|
|
||||||
}
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_dup(old_fd: FileDesc) -> Result<isize> {
|
|
||||||
let new_fd = fs::do_dup(old_fd)?;
|
|
||||||
Ok(new_fd as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result<isize> {
|
|
||||||
let new_fd = fs::do_dup2(old_fd, new_fd)?;
|
|
||||||
Ok(new_fd as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_dup3(old_fd: FileDesc, new_fd: FileDesc, flags: u32) -> Result<isize> {
|
|
||||||
let new_fd = fs::do_dup3(old_fd, new_fd, flags)?;
|
|
||||||
Ok(new_fd as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: handle tz: timezone_t
|
// TODO: handle tz: timezone_t
|
||||||
fn do_gettimeofday(tv_u: *mut timeval_t) -> Result<isize> {
|
fn do_gettimeofday(tv_u: *mut timeval_t) -> Result<isize> {
|
||||||
check_mut_ptr(tv_u)?;
|
check_mut_ptr(tv_u)?;
|
||||||
@ -921,101 +696,6 @@ fn do_getcwd(buf: *mut u8, size: usize) -> Result<isize> {
|
|||||||
Ok(buf as isize)
|
Ok(buf as isize)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_chdir(path: *const i8) -> Result<isize> {
|
|
||||||
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
|
||||||
fs::do_chdir(&path)?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_rename(oldpath: *const i8, newpath: *const i8) -> Result<isize> {
|
|
||||||
let oldpath = clone_cstring_safely(oldpath)?
|
|
||||||
.to_string_lossy()
|
|
||||||
.into_owned();
|
|
||||||
let newpath = clone_cstring_safely(newpath)?
|
|
||||||
.to_string_lossy()
|
|
||||||
.into_owned();
|
|
||||||
fs::do_rename(&oldpath, &newpath)?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_mkdir(path: *const i8, mode: usize) -> Result<isize> {
|
|
||||||
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
|
||||||
fs::do_mkdir(&path, mode)?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_rmdir(path: *const i8) -> Result<isize> {
|
|
||||||
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
|
||||||
fs::do_rmdir(&path)?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_link(oldpath: *const i8, newpath: *const i8) -> Result<isize> {
|
|
||||||
let oldpath = clone_cstring_safely(oldpath)?
|
|
||||||
.to_string_lossy()
|
|
||||||
.into_owned();
|
|
||||||
let newpath = clone_cstring_safely(newpath)?
|
|
||||||
.to_string_lossy()
|
|
||||||
.into_owned();
|
|
||||||
fs::do_link(&oldpath, &newpath)?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_unlink(path: *const i8) -> Result<isize> {
|
|
||||||
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
|
||||||
fs::do_unlink(&path)?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_readlink(path: *const i8, buf: *mut u8, size: usize) -> Result<isize> {
|
|
||||||
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
|
||||||
let buf = {
|
|
||||||
check_array(buf, size)?;
|
|
||||||
unsafe { std::slice::from_raw_parts_mut(buf, size) }
|
|
||||||
};
|
|
||||||
let len = fs::do_readlink(&path, buf)?;
|
|
||||||
Ok(len as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_sendfile(
|
|
||||||
out_fd: FileDesc,
|
|
||||||
in_fd: FileDesc,
|
|
||||||
offset_ptr: *mut off_t,
|
|
||||||
count: usize,
|
|
||||||
) -> Result<isize> {
|
|
||||||
let offset = if offset_ptr.is_null() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
check_mut_ptr(offset_ptr)?;
|
|
||||||
Some(unsafe { offset_ptr.read() })
|
|
||||||
};
|
|
||||||
|
|
||||||
let (len, offset) = fs::do_sendfile(out_fd, in_fd, offset, count)?;
|
|
||||||
if !offset_ptr.is_null() {
|
|
||||||
unsafe {
|
|
||||||
offset_ptr.write(offset as off_t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(len as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_fcntl(fd: FileDesc, cmd: u32, arg: u64) -> Result<isize> {
|
|
||||||
let cmd = FcntlCmd::from_raw(cmd, arg)?;
|
|
||||||
fs::do_fcntl(fd, &cmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_ioctl(fd: FileDesc, cmd: u32, argp: *mut u8) -> Result<isize> {
|
|
||||||
info!("ioctl: fd: {}, cmd: {}, argp: {:?}", fd, cmd, argp);
|
|
||||||
let mut ioctl_cmd = unsafe {
|
|
||||||
if argp.is_null() == false {
|
|
||||||
check_mut_ptr(argp)?;
|
|
||||||
}
|
|
||||||
IoctlCmd::new(cmd, argp)?
|
|
||||||
};
|
|
||||||
fs::do_ioctl(fd, &mut ioctl_cmd)?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_arch_prctl(code: u32, addr: *mut usize) -> Result<isize> {
|
fn do_arch_prctl(code: u32, addr: *mut usize) -> Result<isize> {
|
||||||
let code = process::ArchPrctlCode::from_u32(code)?;
|
let code = process::ArchPrctlCode::from_u32(code)?;
|
||||||
check_mut_ptr(addr)?;
|
check_mut_ptr(addr)?;
|
||||||
@ -1406,117 +1086,6 @@ fn do_socketpair(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_select(
|
|
||||||
nfds: c_int,
|
|
||||||
readfds: *mut libc::fd_set,
|
|
||||||
writefds: *mut libc::fd_set,
|
|
||||||
exceptfds: *mut libc::fd_set,
|
|
||||||
timeout: *const libc::timeval,
|
|
||||||
) -> Result<isize> {
|
|
||||||
// check arguments
|
|
||||||
if nfds < 0 || nfds >= libc::FD_SETSIZE as c_int {
|
|
||||||
return_errno!(EINVAL, "nfds is negative or exceeds the resource limit");
|
|
||||||
}
|
|
||||||
let nfds = nfds as usize;
|
|
||||||
|
|
||||||
let mut zero_fds0: libc::fd_set = unsafe { core::mem::zeroed() };
|
|
||||||
let mut zero_fds1: libc::fd_set = unsafe { core::mem::zeroed() };
|
|
||||||
let mut zero_fds2: libc::fd_set = unsafe { core::mem::zeroed() };
|
|
||||||
|
|
||||||
let readfds = if !readfds.is_null() {
|
|
||||||
check_mut_ptr(readfds)?;
|
|
||||||
unsafe { &mut *readfds }
|
|
||||||
} else {
|
|
||||||
&mut zero_fds0
|
|
||||||
};
|
|
||||||
let writefds = if !writefds.is_null() {
|
|
||||||
check_mut_ptr(writefds)?;
|
|
||||||
unsafe { &mut *writefds }
|
|
||||||
} else {
|
|
||||||
&mut zero_fds1
|
|
||||||
};
|
|
||||||
let exceptfds = if !exceptfds.is_null() {
|
|
||||||
check_mut_ptr(exceptfds)?;
|
|
||||||
unsafe { &mut *exceptfds }
|
|
||||||
} else {
|
|
||||||
&mut zero_fds2
|
|
||||||
};
|
|
||||||
let timeout = if !timeout.is_null() {
|
|
||||||
check_ptr(timeout)?;
|
|
||||||
Some(unsafe { timeout.read() })
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let n = fs::do_select(nfds, readfds, writefds, exceptfds, timeout)?;
|
|
||||||
Ok(n as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_poll(fds: *mut libc::pollfd, nfds: libc::nfds_t, timeout: c_int) -> Result<isize> {
|
|
||||||
check_mut_array(fds, nfds as usize)?;
|
|
||||||
let polls = unsafe { std::slice::from_raw_parts_mut(fds, nfds as usize) };
|
|
||||||
|
|
||||||
let n = fs::do_poll(polls, timeout)?;
|
|
||||||
Ok(n as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_epoll_create(size: c_int) -> Result<isize> {
|
|
||||||
if size <= 0 {
|
|
||||||
return_errno!(EINVAL, "size is not positive");
|
|
||||||
}
|
|
||||||
do_epoll_create1(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_epoll_create1(flags: c_int) -> Result<isize> {
|
|
||||||
let fd = fs::do_epoll_create1(flags)?;
|
|
||||||
Ok(fd as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_epoll_ctl(
|
|
||||||
epfd: c_int,
|
|
||||||
op: c_int,
|
|
||||||
fd: c_int,
|
|
||||||
event: *const libc::epoll_event,
|
|
||||||
) -> Result<isize> {
|
|
||||||
if !event.is_null() {
|
|
||||||
check_ptr(event)?;
|
|
||||||
}
|
|
||||||
fs::do_epoll_ctl(epfd as FileDesc, op, fd as FileDesc, event)?;
|
|
||||||
Ok(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_epoll_wait(
|
|
||||||
epfd: c_int,
|
|
||||||
events: *mut libc::epoll_event,
|
|
||||||
maxevents: c_int,
|
|
||||||
timeout: c_int,
|
|
||||||
) -> Result<isize> {
|
|
||||||
let maxevents = {
|
|
||||||
if maxevents <= 0 {
|
|
||||||
return_errno!(EINVAL, "maxevents <= 0");
|
|
||||||
}
|
|
||||||
maxevents as usize
|
|
||||||
};
|
|
||||||
let events = {
|
|
||||||
check_mut_array(events, maxevents)?;
|
|
||||||
unsafe { std::slice::from_raw_parts_mut(events, maxevents) }
|
|
||||||
};
|
|
||||||
let count = fs::do_epoll_wait(epfd as FileDesc, events, timeout)?;
|
|
||||||
Ok(count as isize)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_epoll_pwait(
|
|
||||||
epfd: c_int,
|
|
||||||
events: *mut libc::epoll_event,
|
|
||||||
maxevents: c_int,
|
|
||||||
timeout: c_int,
|
|
||||||
sigmask: *const usize, //TODO:add sigset_t
|
|
||||||
) -> Result<isize> {
|
|
||||||
info!("epoll_pwait");
|
|
||||||
//TODO:add signal support
|
|
||||||
do_epoll_wait(epfd, events, maxevents, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_uname(name: *mut utsname_t) -> Result<isize> {
|
fn do_uname(name: *mut utsname_t) -> Result<isize> {
|
||||||
check_mut_ptr(name)?;
|
check_mut_ptr(name)?;
|
||||||
let name = unsafe { &mut *name };
|
let name = unsafe { &mut *name };
|
||||||
@ -1549,26 +1118,6 @@ fn do_prlimit(
|
|||||||
misc::do_prlimit(pid, resource, new_limit, old_limit).map(|_| 0)
|
misc::do_prlimit(pid, resource, new_limit, old_limit).map(|_| 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_access(path: *const i8, mode: u32) -> Result<isize> {
|
|
||||||
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
|
||||||
let mode = AccessModes::from_u32(mode)?;
|
|
||||||
fs::do_access(&path, mode).map(|_| 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn do_faccessat(dirfd: i32, path: *const i8, mode: u32, flags: u32) -> Result<isize> {
|
|
||||||
let dirfd = if dirfd >= 0 {
|
|
||||||
Some(dirfd as FileDesc)
|
|
||||||
} else if dirfd == AT_FDCWD {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
return_errno!(EINVAL, "invalid dirfd");
|
|
||||||
};
|
|
||||||
let path = clone_cstring_safely(path)?.to_string_lossy().into_owned();
|
|
||||||
let mode = AccessModes::from_u32(mode)?;
|
|
||||||
let flags = AccessFlags::from_u32(flags)?;
|
|
||||||
fs::do_faccessat(dirfd, &path, mode, flags).map(|_| 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: implement signals
|
// TODO: implement signals
|
||||||
|
|
||||||
fn do_rt_sigaction() -> Result<isize> {
|
fn do_rt_sigaction() -> Result<isize> {
|
||||||
|
Loading…
Reference in New Issue
Block a user