diff --git a/src/libos/src/fs/dev_null.rs b/src/libos/src/fs/dev_fs/dev_null.rs similarity index 100% rename from src/libos/src/fs/dev_null.rs rename to src/libos/src/fs/dev_fs/dev_null.rs diff --git a/src/libos/src/fs/dev_random.rs b/src/libos/src/fs/dev_fs/dev_random.rs similarity index 100% rename from src/libos/src/fs/dev_random.rs rename to src/libos/src/fs/dev_fs/dev_random.rs diff --git a/src/libos/src/fs/dev_sgx/attestation/mod.rs b/src/libos/src/fs/dev_fs/dev_sgx/attestation/mod.rs similarity index 100% rename from src/libos/src/fs/dev_sgx/attestation/mod.rs rename to src/libos/src/fs/dev_fs/dev_sgx/attestation/mod.rs diff --git a/src/libos/src/fs/dev_sgx/attestation/sgx_attestation_agent.rs b/src/libos/src/fs/dev_fs/dev_sgx/attestation/sgx_attestation_agent.rs similarity index 100% rename from src/libos/src/fs/dev_sgx/attestation/sgx_attestation_agent.rs rename to src/libos/src/fs/dev_fs/dev_sgx/attestation/sgx_attestation_agent.rs diff --git a/src/libos/src/fs/dev_sgx/attestation/sgx_quote.rs b/src/libos/src/fs/dev_fs/dev_sgx/attestation/sgx_quote.rs similarity index 100% rename from src/libos/src/fs/dev_sgx/attestation/sgx_quote.rs rename to src/libos/src/fs/dev_fs/dev_sgx/attestation/sgx_quote.rs diff --git a/src/libos/src/fs/dev_sgx/consts.rs b/src/libos/src/fs/dev_fs/dev_sgx/consts.rs similarity index 100% rename from src/libos/src/fs/dev_sgx/consts.rs rename to src/libos/src/fs/dev_fs/dev_sgx/consts.rs diff --git a/src/libos/src/fs/dev_sgx/mod.rs b/src/libos/src/fs/dev_fs/dev_sgx/mod.rs similarity index 100% rename from src/libos/src/fs/dev_sgx/mod.rs rename to src/libos/src/fs/dev_fs/dev_sgx/mod.rs diff --git a/src/libos/src/fs/dev_zero.rs b/src/libos/src/fs/dev_fs/dev_zero.rs similarity index 100% rename from src/libos/src/fs/dev_zero.rs rename to src/libos/src/fs/dev_fs/dev_zero.rs diff --git a/src/libos/src/fs/dev_fs/mod.rs b/src/libos/src/fs/dev_fs/mod.rs new file mode 100644 index 00000000..af1695dc --- /dev/null +++ b/src/libos/src/fs/dev_fs/mod.rs @@ -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; diff --git a/src/libos/src/fs/file.rs b/src/libos/src/fs/file.rs index 5618ffa2..8fd69c6f 100644 --- a/src/libos/src/fs/file.rs +++ b/src/libos/src/fs/file.rs @@ -1,8 +1,4 @@ use super::*; -use std; -use std::borrow::BorrowMut; -use std::fmt; -use std::io::SeekFrom; macro_rules! return_op_unsupported_error { ($op_name: expr, $errno: expr) => {{ @@ -88,436 +84,6 @@ pub trait File: Debug + Sync + Send + Any { pub type FileRef = Arc>; -#[derive(Debug)] -#[repr(C)] -pub struct SgxFile { - inner: SgxMutex, -} - -impl SgxFile { - pub fn new( - file: Arc>, - is_readable: bool, - is_writable: bool, - is_append: bool, - ) -> Result { - 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 { - let mut inner_guard = self.inner.lock().unwrap(); - let inner = inner_guard.borrow_mut(); - inner.read(buf) - } - - fn write(&self, buf: &[u8]) -> Result { - 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 { - 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 { - 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 { - let mut inner_guard = self.inner.lock().unwrap(); - let inner = inner_guard.borrow_mut(); - inner.readv(bufs) - } - - fn writev(&self, bufs: &[&[u8]]) -> Result { - let mut inner_guard = self.inner.lock().unwrap(); - let inner = inner_guard.borrow_mut(); - inner.writev(bufs) - } - - fn seek(&self, pos: SeekFrom) -> Result { - 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>, - is_readable: bool, - is_writable: bool, - is_append: bool, -} - -impl SgxFileInner { - pub fn write(&mut self, buf: &[u8]) -> Result { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - self.write(buf) - } - - fn writev(&self, bufs: &[&[u8]]) -> Result { - 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 { - 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 { - let read_len = { self.inner.lock().read(buf).map_err(|e| errno!(e))? }; - Ok(read_len) - } - - fn readv(&self, bufs: &mut [&mut [u8]]) -> Result { - 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 { - Ok(Metadata { - dev: 0, - inode: 0, - size: 0, - blk_size: 0, - blocks: 0, - atime: Timespec { sec: 0, nsec: 0 }, - mtime: Timespec { sec: 0, nsec: 0 }, - ctime: Timespec { sec: 0, nsec: 0 }, - type_: FileType::CharDevice, - mode: 0, - nlinks: 0, - uid: 0, - gid: 0, - rdev: 0, - }) - } - - fn as_any(&self) -> &dyn Any { - self - } -} - -impl Debug for StdinFile { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "StdinFile") - } -} - -unsafe impl Send for StdinFile {} -unsafe impl Sync for StdinFile {} - #[derive(Copy, Clone, Debug)] struct FileOpNotSupportedError { errno: Errno, diff --git a/src/libos/src/fs/access.rs b/src/libos/src/fs/file_ops/access.rs similarity index 59% rename from src/libos/src/fs/access.rs rename to src/libos/src/fs/file_ops/access.rs index 1d7eaa5f..5140096b 100644 --- a/src/libos/src/fs/access.rs +++ b/src/libos/src/fs/file_ops/access.rs @@ -1,32 +1,29 @@ use super::*; -//int faccessat(int dirfd, const char *pathname, int mode, int flags); -//int access(const char *pathname, int mode); - bitflags! { - pub struct AccessModes : u32 { + pub struct AccessibilityCheckMode : u32 { const X_OK = 1; const W_OK = 2; const R_OK = 4; } } -impl AccessModes { - pub fn from_u32(bits: u32) -> Result { - AccessModes::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid mode")) +impl AccessibilityCheckMode { + pub fn from_u32(bits: u32) -> Result { + AccessibilityCheckMode::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid mode")) } } bitflags! { - pub struct AccessFlags : u32 { + pub struct AccessibilityCheckFlags : u32 { const AT_SYMLINK_NOFOLLOW = 0x100; const AT_EACCESS = 0x200; } } -impl AccessFlags { - pub fn from_u32(bits: u32) -> Result { - AccessFlags::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid flags")) +impl AccessibilityCheckFlags { + pub fn from_u32(bits: u32) -> Result { + AccessibilityCheckFlags::from_bits(bits).ok_or_else(|| errno!(EINVAL, "invalid flags")) } } @@ -35,8 +32,8 @@ pub const AT_FDCWD: i32 = -100; pub fn do_faccessat( dirfd: Option, path: &str, - mode: AccessModes, - flags: AccessFlags, + mode: AccessibilityCheckMode, + flags: AccessibilityCheckFlags, ) -> Result<()> { info!( "faccessat: dirfd: {:?}, path: {:?}, mode: {:?}, flags: {:?}", @@ -49,7 +46,7 @@ pub fn do_faccessat( } } -pub fn do_access(path: &str, mode: AccessModes) -> Result<()> { +pub fn do_access(path: &str, mode: AccessibilityCheckMode) -> Result<()> { info!("access: path: {:?}, mode: {:?}", path, mode); let current_ref = process::get_current(); let mut current = current_ref.lock().unwrap(); diff --git a/src/libos/src/fs/file_ops/chdir.rs b/src/libos/src/fs/file_ops/chdir.rs new file mode 100644 index 00000000..1ec25d1d --- /dev/null +++ b/src/libos/src/fs/file_ops/chdir.rs @@ -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(()) +} diff --git a/src/libos/src/fs/file_ops/close.rs b/src/libos/src/fs/file_ops/close.rs new file mode 100644 index 00000000..efcf1ea0 --- /dev/null +++ b/src/libos/src/fs/file_ops/close.rs @@ -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(()) +} diff --git a/src/libos/src/fs/file_ops/dirent.rs b/src/libos/src/fs/file_ops/dirent.rs new file mode 100644 index 00000000..2b8d687f --- /dev/null +++ b/src/libos/src/fs/file_ops/dirent.rs @@ -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::() + 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 { + 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) +} diff --git a/src/libos/src/fs/file_ops/dup.rs b/src/libos/src/fs/file_ops/dup.rs new file mode 100644 index 00000000..cdf4dd4a --- /dev/null +++ b/src/libos/src/fs/file_ops/dup.rs @@ -0,0 +1,37 @@ +use super::*; + +pub fn do_dup(old_fd: FileDesc) -> Result { + 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 { + 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 { + 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) +} diff --git a/src/libos/src/fs/fcntl.rs b/src/libos/src/fs/file_ops/fcntl.rs similarity index 90% rename from src/libos/src/fs/fcntl.rs rename to src/libos/src/fs/file_ops/fcntl.rs index 46098d9d..f9898764 100644 --- a/src/libos/src/fs/fcntl.rs +++ b/src/libos/src/fs/file_ops/fcntl.rs @@ -1,5 +1,4 @@ use super::*; -use process::FileTableRef; #[derive(Debug)] pub enum FcntlCmd { @@ -34,7 +33,11 @@ impl FcntlCmd { } } -pub fn do_fcntl(file_table_ref: &FileTableRef, fd: FileDesc, cmd: &FcntlCmd) -> Result { +pub fn do_fcntl(fd: FileDesc, cmd: &FcntlCmd) -> Result { + info!("fcntl: fd: {:?}, cmd: {:?}", &fd, cmd); + let current_ref = process::get_current(); + let mut current = current_ref.lock().unwrap(); + let file_table_ref = current.get_files(); let mut file_table = file_table_ref.lock().unwrap(); let ret = match cmd { FcntlCmd::DupFd(min_fd) => { diff --git a/src/libos/src/fs/file_flags.rs b/src/libos/src/fs/file_ops/file_flags.rs similarity index 100% rename from src/libos/src/fs/file_flags.rs rename to src/libos/src/fs/file_ops/file_flags.rs diff --git a/src/libos/src/fs/file_ops/fsync.rs b/src/libos/src/fs/file_ops/fsync.rs new file mode 100644 index 00000000..5e126271 --- /dev/null +++ b/src/libos/src/fs/file_ops/fsync.rs @@ -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(()) +} diff --git a/src/libos/src/fs/ioctl/builtin.rs b/src/libos/src/fs/file_ops/ioctl/builtin.rs similarity index 100% rename from src/libos/src/fs/ioctl/builtin.rs rename to src/libos/src/fs/file_ops/ioctl/builtin.rs diff --git a/src/libos/src/fs/ioctl/macros.rs b/src/libos/src/fs/file_ops/ioctl/macros.rs similarity index 100% rename from src/libos/src/fs/ioctl/macros.rs rename to src/libos/src/fs/file_ops/ioctl/macros.rs diff --git a/src/libos/src/fs/ioctl/mod.rs b/src/libos/src/fs/file_ops/ioctl/mod.rs similarity index 87% rename from src/libos/src/fs/ioctl/mod.rs rename to src/libos/src/fs/file_ops/ioctl/mod.rs index 501bdb2f..1257674c 100644 --- a/src/libos/src/fs/ioctl/mod.rs +++ b/src/libos/src/fs/file_ops/ioctl/mod.rs @@ -63,3 +63,11 @@ impl<'a> IoctlCmd<'a> { Ok(()) } } + +pub fn do_ioctl(fd: FileDesc, cmd: &mut IoctlCmd) -> Result<()> { + info!("ioctl: fd: {}, cmd: {:?}", fd, cmd); + let current_ref = process::get_current(); + let current_process = current_ref.lock().unwrap(); + let file_ref = current_process.get_files().lock().unwrap().get(fd)?; + file_ref.ioctl(cmd) +} diff --git a/src/libos/src/fs/ioctl/non_builtin.rs b/src/libos/src/fs/file_ops/ioctl/non_builtin.rs similarity index 100% rename from src/libos/src/fs/ioctl/non_builtin.rs rename to src/libos/src/fs/file_ops/ioctl/non_builtin.rs diff --git a/src/libos/src/fs/file_ops/link.rs b/src/libos/src/fs/file_ops/link.rs new file mode 100644 index 00000000..32c6e3e3 --- /dev/null +++ b/src/libos/src/fs/file_ops/link.rs @@ -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(()) +} diff --git a/src/libos/src/fs/file_ops/lseek.rs b/src/libos/src/fs/file_ops/lseek.rs new file mode 100644 index 00000000..c8882ae5 --- /dev/null +++ b/src/libos/src/fs/file_ops/lseek.rs @@ -0,0 +1,8 @@ +use super::*; + +pub fn do_lseek(fd: FileDesc, offset: SeekFrom) -> Result { + 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) +} diff --git a/src/libos/src/fs/file_ops/mkdir.rs b/src/libos/src/fs/file_ops/mkdir.rs new file mode 100644 index 00000000..96b8f0d9 --- /dev/null +++ b/src/libos/src/fs/file_ops/mkdir.rs @@ -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(()) +} diff --git a/src/libos/src/fs/file_ops/mod.rs b/src/libos/src/fs/file_ops/mod.rs new file mode 100644 index 00000000..18d53619 --- /dev/null +++ b/src/libos/src/fs/file_ops/mod.rs @@ -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> { + 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> { + 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) +} diff --git a/src/libos/src/fs/file_ops/open.rs b/src/libos/src/fs/file_ops/open.rs new file mode 100644 index 00000000..d7474d44 --- /dev/null +++ b/src/libos/src/fs/file_ops/open.rs @@ -0,0 +1,23 @@ +use super::*; + +pub fn do_open(path: &str, flags: u32, mode: u32) -> Result { + 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> = 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) +} diff --git a/src/libos/src/fs/file_ops/read.rs b/src/libos/src/fs/file_ops/read.rs new file mode 100644 index 00000000..84a0a4bb --- /dev/null +++ b/src/libos/src/fs/file_ops/read.rs @@ -0,0 +1,25 @@ +use super::*; + +pub fn do_read(fd: FileDesc, buf: &mut [u8]) -> Result { + 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 { + 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 { + 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) +} diff --git a/src/libos/src/fs/file_ops/rename.rs b/src/libos/src/fs/file_ops/rename.rs new file mode 100644 index 00000000..41b6cead --- /dev/null +++ b/src/libos/src/fs/file_ops/rename.rs @@ -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(()) +} diff --git a/src/libos/src/fs/file_ops/rmdir.rs b/src/libos/src/fs/file_ops/rmdir.rs new file mode 100644 index 00000000..b4801154 --- /dev/null +++ b/src/libos/src/fs/file_ops/rmdir.rs @@ -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(()) +} diff --git a/src/libos/src/fs/file_ops/sendfile.rs b/src/libos/src/fs/file_ops/sendfile.rs new file mode 100644 index 00000000..1c59d167 --- /dev/null +++ b/src/libos/src/fs/file_ops/sendfile.rs @@ -0,0 +1,52 @@ +use super::*; + +pub fn do_sendfile( + out_fd: FileDesc, + in_fd: FileDesc, + offset: Option, + 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)) +} diff --git a/src/libos/src/fs/file_ops/stat.rs b/src/libos/src/fs/file_ops/stat.rs new file mode 100644 index 00000000..0d030284 --- /dev/null +++ b/src/libos/src/fs/file_ops/stat.rs @@ -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 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 { + warn!("stat is partial implemented as lstat"); + do_lstat(path) +} + +pub fn do_fstat(fd: u32) -> Result { + 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 { + 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) +} diff --git a/src/libos/src/fs/file_ops/symlink.rs b/src/libos/src/fs/file_ops/symlink.rs new file mode 100644 index 00000000..4b381a8c --- /dev/null +++ b/src/libos/src/fs/file_ops/symlink.rs @@ -0,0 +1,32 @@ +use super::*; + +pub fn do_readlink(path: &str, buf: &mut [u8]) -> Result { + 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::() + .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) +} diff --git a/src/libos/src/fs/file_ops/truncate.rs b/src/libos/src/fs/file_ops/truncate.rs new file mode 100644 index 00000000..fd53e5ec --- /dev/null +++ b/src/libos/src/fs/file_ops/truncate.rs @@ -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(()) +} diff --git a/src/libos/src/fs/file_ops/unlink.rs b/src/libos/src/fs/file_ops/unlink.rs new file mode 100644 index 00000000..af50d1fc --- /dev/null +++ b/src/libos/src/fs/file_ops/unlink.rs @@ -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(()) +} diff --git a/src/libos/src/fs/file_ops/write.rs b/src/libos/src/fs/file_ops/write.rs new file mode 100644 index 00000000..a8ae8825 --- /dev/null +++ b/src/libos/src/fs/file_ops/write.rs @@ -0,0 +1,25 @@ +use super::*; + +pub fn do_write(fd: FileDesc, buf: &[u8]) -> Result { + 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 { + 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 { + 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) +} diff --git a/src/libos/src/fs/file_table.rs b/src/libos/src/fs/file_table.rs index 04813aa4..4336044b 100644 --- a/src/libos/src/fs/file_table.rs +++ b/src/libos/src/fs/file_table.rs @@ -1,6 +1,4 @@ -use super::file::{File, FileRef}; use super::*; -use std; pub type FileDesc = u32; diff --git a/src/libos/src/fs/fs_ops/mod.rs b/src/libos/src/fs/fs_ops/mod.rs new file mode 100644 index 00000000..7d08bb94 --- /dev/null +++ b/src/libos/src/fs/fs_ops/mod.rs @@ -0,0 +1,5 @@ +use super::*; + +pub use self::sync::do_sync; + +mod sync; diff --git a/src/libos/src/fs/fs_ops/sync.rs b/src/libos/src/fs/fs_ops/sync.rs new file mode 100644 index 00000000..2de54a5b --- /dev/null +++ b/src/libos/src/fs/fs_ops/sync.rs @@ -0,0 +1,7 @@ +use super::*; + +pub fn do_sync() -> Result<()> { + info!("sync:"); + ROOT_INODE.fs().sync()?; + Ok(()) +} diff --git a/src/libos/src/fs/inode_file.rs b/src/libos/src/fs/inode_file.rs index f7087b92..b3aa8c42 100644 --- a/src/libos/src/fs/inode_file.rs +++ b/src/libos/src/fs/inode_file.rs @@ -1,7 +1,6 @@ use super::*; use rcore_fs_sefs::dev::SefsMac; -use sgx_trts::libc::S_IRUSR; -use std::fmt; +use sgx_trts::libc::{S_IRUSR, S_IWUSR}; pub struct INodeFile { inode: Arc, diff --git a/src/libos/src/fs/mod.rs b/src/libos/src/fs/mod.rs index 9161fb0c..50116b28 100644 --- a/src/libos/src/fs/mod.rs +++ b/src/libos/src/fs/mod.rs @@ -1,756 +1,32 @@ use super::*; -use net::{AsSocket, SocketFile}; -use process::Process; -use rcore_fs::vfs::{FileType, FsError, INode, Metadata, Timespec}; -use std::io::{Read, Seek, SeekFrom, Write}; -use std::sgxfs as fs_impl; -use {process, std}; - -pub use self::access::{do_access, do_faccessat, AccessFlags, AccessModes, AT_FDCWD}; -use self::dev_null::DevNull; -use self::dev_random::DevRandom; -use self::dev_sgx::DevSgx; -use self::dev_zero::DevZero; -pub use self::fcntl::FcntlCmd; -pub use self::file::{File, FileRef, SgxFile, StdinFile, StdoutFile}; -pub use self::file_flags::{AccessMode, CreationFlags, StatusFlags}; -pub use self::file_table::{FileDesc, FileTable}; -pub use self::inode_file::{AsINodeFile, INodeExt, INodeFile}; -pub use self::io_multiplexing::*; -pub use self::ioctl::*; -pub use self::pipe::Pipe; -pub use self::root_inode::ROOT_INODE; -pub use self::unix_socket::{AsUnixSocket, UnixSocketFile}; -use sgx_trts::libc::S_IWUSR; +use process; +use rcore_fs::vfs::{FileSystem, FileType, FsError, INode, Metadata, Timespec}; +use std; use std::any::Any; +use std::fmt; +use std::io::{Read, Seek, SeekFrom, Write}; use std::mem::MaybeUninit; -mod access; -mod dev_null; -mod dev_random; -mod dev_sgx; -mod dev_zero; -mod fcntl; +pub use self::file::{File, FileRef}; +pub use self::file_ops::{AccessMode, CreationFlags, Stat, StatusFlags}; +pub use self::file_ops::{IoctlCmd, StructuredIoctlArgType, StructuredIoctlNum}; +pub use self::file_table::{FileDesc, FileTable}; +pub use self::inode_file::{AsINodeFile, INodeExt, INodeFile}; +pub use self::pipe::Pipe; +pub use self::rootfs::ROOT_INODE; +pub use self::stdio::{StdinFile, StdoutFile}; +pub use self::syscalls::*; + +mod dev_fs; mod file; -mod file_flags; +mod file_ops; mod file_table; +mod fs_ops; mod hostfs; mod inode_file; -mod io_multiplexing; -mod ioctl; mod pipe; -mod root_inode; -mod sgx_impl; -mod unix_socket; - -pub fn do_open(path: &str, flags: u32, mode: u32) -> Result { - 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> = 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - warn!("stat is partial implemented as lstat"); - do_lstat(path) -} - -pub fn do_fstat(fd: u32) -> Result { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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, - 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> { - 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> { - 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::() + 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 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 { - 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 { - 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::() - .map_err(|e| errno!(EBADF, "Invalid file descriptor"))?; - let current_ref = process::get_current(); - let current = current_ref.lock().unwrap(); - let file_ref = current.get_files().lock().unwrap().get(fd)?; - if let Ok(inode_file) = file_ref.as_inode_file() { - inode_file.get_abs_path().to_owned() - } else { - // TODO: support special device files - return_errno!(EINVAL, "not a normal file link") - } - } else { - // TODO: support symbolic links - return_errno!(EINVAL, "not a symbolic link") - } - }; - let len = file_path.len().min(buf.len()); - buf[0..len].copy_from_slice(&file_path.as_bytes()[0..len]); - Ok(len) -} +mod rootfs; +mod sefs; +mod stdio; +mod syscalls; diff --git a/src/libos/src/fs/pipe.rs b/src/libos/src/fs/pipe.rs index 50a9c949..68a2390f 100644 --- a/src/libos/src/fs/pipe.rs +++ b/src/libos/src/fs/pipe.rs @@ -154,3 +154,19 @@ impl File for PipeWriter { unsafe impl Send for PipeWriter {} unsafe impl Sync for PipeWriter {} + +pub fn do_pipe2(flags: u32) -> Result<[FileDesc; 2]> { + info!("pipe2: flags: {:#x}", flags); + let creation_flags = CreationFlags::from_bits_truncate(flags); + let current_ref = process::get_current(); + let current = current_ref.lock().unwrap(); + let pipe = Pipe::new(StatusFlags::from_bits_truncate(flags))?; + + let file_table_ref = current.get_files(); + let mut file_table = file_table_ref.lock().unwrap(); + let close_on_spawn = creation_flags.must_close_on_spawn(); + let reader_fd = file_table.put(Arc::new(Box::new(pipe.reader)), close_on_spawn); + let writer_fd = file_table.put(Arc::new(Box::new(pipe.writer)), close_on_spawn); + info!("pipe2: reader_fd: {}, writer_fd: {}", reader_fd, writer_fd); + Ok([reader_fd, writer_fd]) +} diff --git a/src/libos/src/fs/root_inode.rs b/src/libos/src/fs/rootfs.rs similarity index 97% rename from src/libos/src/fs/root_inode.rs rename to src/libos/src/fs/rootfs.rs index 0bb1ab12..1cc6bcdc 100644 --- a/src/libos/src/fs/root_inode.rs +++ b/src/libos/src/fs/rootfs.rs @@ -1,10 +1,9 @@ use super::hostfs::HostFS; -use super::sgx_impl::{SgxStorage, SgxUuidProvider}; +use super::sefs::{SgxStorage, SgxUuidProvider}; use super::*; use config::{ConfigMount, ConfigMountFsType}; use std::path::{Path, PathBuf}; -use rcore_fs::vfs::{FileSystem, FileType, FsError, INode}; use rcore_fs_mountfs::{MNode, MountFS}; use rcore_fs_ramfs::RamFS; use rcore_fs_sefs::dev::*; diff --git a/src/libos/src/fs/sefs/mod.rs b/src/libos/src/fs/sefs/mod.rs new file mode 100644 index 00000000..accd709d --- /dev/null +++ b/src/libos/src/fs/sefs/mod.rs @@ -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; diff --git a/src/libos/src/fs/sgx_impl.rs b/src/libos/src/fs/sefs/sgx_storage.rs similarity index 91% rename from src/libos/src/fs/sgx_impl.rs rename to src/libos/src/fs/sefs/sgx_storage.rs index 62f4b51e..8b024bb0 100644 --- a/src/libos/src/fs/sgx_impl.rs +++ b/src/libos/src/fs/sefs/sgx_storage.rs @@ -1,38 +1,13 @@ -use super::sgx_aes_gcm_128bit_tag_t; -use alloc::string::ToString; -use rcore_fs::dev::TimeProvider; -use rcore_fs::vfs::Timespec; -use rcore_fs_sefs::dev::*; -use sgx_trts::libc; -use sgx_types::*; +use super::*; +use rcore_fs_sefs::dev::{DevResult, DeviceError, File, SefsMac, Storage}; use std::boxed::Box; +use std::collections::hash_map::DefaultHasher; use std::collections::BTreeMap; +use std::hash::{Hash, Hasher}; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; use std::sgxfs::{remove, OpenOptions, SgxFile}; -use std::string::String; use std::sync::{Arc, SgxMutex as Mutex}; -use std::time::{SystemTime, UNIX_EPOCH}; - -use std::collections::hash_map::DefaultHasher; -use std::hash::{Hash, Hasher}; - -extern "C" { - fn sgx_read_rand(rand_buf: *mut u8, buf_size: usize) -> sgx_status_t; -} - -pub struct SgxUuidProvider; - -impl UuidProvider for SgxUuidProvider { - fn generate_uuid(&self) -> SefsUuid { - let mut uuid: [u8; 16] = [0u8; 16]; - let buf = uuid.as_mut_ptr(); - let size = 16; - let status = unsafe { sgx_read_rand(buf, size) }; - assert!(status == sgx_status_t::SGX_SUCCESS); - SefsUuid(uuid) - } -} pub struct SgxStorage { path: PathBuf, diff --git a/src/libos/src/fs/sefs/sgx_uuid_provider.rs b/src/libos/src/fs/sefs/sgx_uuid_provider.rs new file mode 100644 index 00000000..f5e889b9 --- /dev/null +++ b/src/libos/src/fs/sefs/sgx_uuid_provider.rs @@ -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) + } +} diff --git a/src/libos/src/fs/stdio.rs b/src/libos/src/fs/stdio.rs new file mode 100644 index 00000000..f76086e3 --- /dev/null +++ b/src/libos/src/fs/stdio.rs @@ -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 { + 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 { + self.write(buf) + } + + fn writev(&self, bufs: &[&[u8]]) -> Result { + 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 { + 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 { + let read_len = { self.inner.lock().read(buf).map_err(|e| errno!(e))? }; + Ok(read_len) + } + + fn readv(&self, bufs: &mut [&mut [u8]]) -> Result { + 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 { + 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 {} diff --git a/src/libos/src/fs/syscalls.rs b/src/libos/src/fs/syscalls.rs new file mode 100644 index 00000000..a0ba8159 --- /dev/null +++ b/src/libos/src/fs/syscalls.rs @@ -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 { + 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 { + file_ops::do_close(fd)?; + Ok(0) +} + +pub fn do_read(fd: FileDesc, buf: *mut u8, size: usize) -> Result { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + file_ops::do_fsync(fd)?; + Ok(0) +} + +pub fn do_fdatasync(fd: FileDesc) -> Result { + file_ops::do_fdatasync(fd)?; + Ok(0) +} + +pub fn do_truncate(path: *const i8, len: usize) -> Result { + 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 { + file_ops::do_ftruncate(fd, len)?; + Ok(0) +} + +pub fn do_getdents64(fd: FileDesc, buf: *mut u8, buf_size: usize) -> Result { + 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 { + fs_ops::do_sync()?; + Ok(0) +} + +pub fn do_pipe2(fds_u: *mut i32, flags: u32) -> Result { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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) +} diff --git a/src/libos/src/fs/io_multiplexing.rs b/src/libos/src/net/io_multiplexing.rs similarity index 99% rename from src/libos/src/fs/io_multiplexing.rs rename to src/libos/src/net/io_multiplexing.rs index 4696973d..7d6539b7 100644 --- a/src/libos/src/fs/io_multiplexing.rs +++ b/src/libos/src/net/io_multiplexing.rs @@ -1,4 +1,5 @@ use super::*; +use fs::{File, FileDesc, FileRef}; use std::any::Any; use std::collections::btree_map::BTreeMap; use std::fmt; diff --git a/src/libos/src/net/mod.rs b/src/libos/src/net/mod.rs index d0ada01f..9441ec1e 100644 --- a/src/libos/src/net/mod.rs +++ b/src/libos/src/net/mod.rs @@ -1,14 +1,17 @@ use super::*; -use std::*; +use std; +mod io_multiplexing; mod iovs; mod msg; mod msg_flags; mod socket_file; mod syscalls; +mod unix_socket; pub use self::iovs::{Iovs, IovsMut, SliceAsLibcIovec}; pub use self::msg::{msghdr, msghdr_mut, MsgHdr, MsgHdrMut}; pub use self::msg_flags::MsgFlags; pub use self::socket_file::{AsSocket, SocketFile}; -pub use self::syscalls::{do_recvmsg, do_sendmsg}; +pub use self::syscalls::*; +pub use self::unix_socket::{AsUnixSocket, UnixSocketFile}; diff --git a/src/libos/src/net/syscalls.rs b/src/libos/src/net/syscalls.rs index f2255afc..9ae77ae5 100644 --- a/src/libos/src/net/syscalls.rs +++ b/src/libos/src/net/syscalls.rs @@ -1,6 +1,7 @@ use super::*; -use fs::{AsUnixSocket, File, FileDesc, FileRef, UnixSocketFile}; +use super::io_multiplexing; +use fs::{File, FileDesc, FileRef}; use process::Process; use util::mem_util::from_user; @@ -124,3 +125,114 @@ impl c_msghdr_ext for msghdr_mut { Ok(()) } } + +pub fn do_select( + nfds: c_int, + readfds: *mut libc::fd_set, + writefds: *mut libc::fd_set, + exceptfds: *mut libc::fd_set, + timeout: *const libc::timeval, +) -> Result { + // 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 { + 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 { + if size <= 0 { + return_errno!(EINVAL, "size is not positive"); + } + do_epoll_create1(0) +} + +pub fn do_epoll_create1(flags: c_int) -> Result { + 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 { + 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 { + 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 { + info!("epoll_pwait"); + //TODO:add signal support + do_epoll_wait(epfd, events, maxevents, 0) +} diff --git a/src/libos/src/fs/unix_socket.rs b/src/libos/src/net/unix_socket.rs similarity index 98% rename from src/libos/src/fs/unix_socket.rs rename to src/libos/src/net/unix_socket.rs index 65fe37ce..d751726c 100644 --- a/src/libos/src/fs/unix_socket.rs +++ b/src/libos/src/net/unix_socket.rs @@ -1,5 +1,7 @@ use super::*; -use alloc::string::ToString; +use fs::{File, FileRef, IoctlCmd}; +use rcore_fs::vfs::{FileType, Metadata, Timespec}; +use std::any::Any; use std::collections::btree_map::BTreeMap; use std::fmt; use std::sync::atomic::{spin_loop_hint, AtomicUsize, Ordering}; diff --git a/src/libos/src/syscall/mod.rs b/src/libos/src/syscall/mod.rs index eebd4350..0bd8fd79 100644 --- a/src/libos/src/syscall/mod.rs +++ b/src/libos/src/syscall/mod.rs @@ -7,12 +7,9 @@ //! 3. Dispatch the syscall to `do_*` (at this file) //! 4. Do some memory checks then call `mod::do_*` (at each module) -use fs::{ - AccessFlags, AccessModes, AsUnixSocket, FcntlCmd, File, FileDesc, FileRef, IoctlCmd, - UnixSocketFile, AT_FDCWD, -}; +use fs::{File, FileDesc, FileRef, Stat}; use misc::{resource_t, rlimit_t, utsname_t}; -use net::{msghdr, msghdr_mut, AsSocket, SocketFile}; +use net::{msghdr, msghdr_mut, AsSocket, AsUnixSocket, SocketFile, UnixSocketFile}; use process::{pid_t, ChildProcessFilter, CloneFlags, CpuSet, FileAction, FutexFlags, FutexOp}; use std::ffi::{CStr, CString}; use std::ptr; @@ -72,81 +69,81 @@ pub extern "C" fn dispatch_syscall( let ret = match num { // file - SYS_OPEN => do_open(arg0 as *const i8, arg1 as u32, arg2 as u32), - SYS_CLOSE => do_close(arg0 as FileDesc), - SYS_READ => do_read(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize), - SYS_WRITE => do_write(arg0 as FileDesc, arg1 as *const u8, arg2 as usize), - SYS_PREAD64 => do_pread( + SYS_OPEN => fs::do_open(arg0 as *const i8, arg1 as u32, arg2 as u32), + SYS_CLOSE => fs::do_close(arg0 as FileDesc), + SYS_READ => fs::do_read(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize), + SYS_WRITE => fs::do_write(arg0 as FileDesc, arg1 as *const u8, arg2 as usize), + SYS_PREAD64 => fs::do_pread( arg0 as FileDesc, arg1 as *mut u8, arg2 as usize, arg3 as usize, ), - SYS_PWRITE64 => do_pwrite( + SYS_PWRITE64 => fs::do_pwrite( arg0 as FileDesc, arg1 as *const u8, arg2 as usize, arg3 as usize, ), - SYS_READV => do_readv(arg0 as FileDesc, arg1 as *mut iovec_t, arg2 as i32), - SYS_WRITEV => do_writev(arg0 as FileDesc, arg1 as *mut iovec_t, arg2 as i32), - SYS_STAT => do_stat(arg0 as *const i8, arg1 as *mut fs::Stat), - SYS_FSTAT => do_fstat(arg0 as FileDesc, arg1 as *mut fs::Stat), - SYS_LSTAT => do_lstat(arg0 as *const i8, arg1 as *mut fs::Stat), - SYS_ACCESS => do_access(arg0 as *const i8, arg1 as u32), - SYS_FACCESSAT => do_faccessat(arg0 as i32, arg1 as *const i8, arg2 as u32, arg3 as u32), - SYS_LSEEK => do_lseek(arg0 as FileDesc, arg1 as off_t, arg2 as i32), - SYS_FSYNC => do_fsync(arg0 as FileDesc), - SYS_FDATASYNC => do_fdatasync(arg0 as FileDesc), - SYS_TRUNCATE => do_truncate(arg0 as *const i8, arg1 as usize), - SYS_FTRUNCATE => do_ftruncate(arg0 as FileDesc, arg1 as usize), - SYS_GETDENTS64 => do_getdents64(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize), - SYS_SYNC => do_sync(), + SYS_READV => fs::do_readv(arg0 as FileDesc, arg1 as *mut fs::iovec_t, arg2 as i32), + SYS_WRITEV => fs::do_writev(arg0 as FileDesc, arg1 as *mut fs::iovec_t, arg2 as i32), + SYS_STAT => fs::do_stat(arg0 as *const i8, arg1 as *mut Stat), + SYS_FSTAT => fs::do_fstat(arg0 as FileDesc, arg1 as *mut Stat), + SYS_LSTAT => fs::do_lstat(arg0 as *const i8, arg1 as *mut Stat), + SYS_ACCESS => fs::do_access(arg0 as *const i8, arg1 as u32), + SYS_FACCESSAT => fs::do_faccessat(arg0 as i32, arg1 as *const i8, arg2 as u32, arg3 as u32), + SYS_LSEEK => fs::do_lseek(arg0 as FileDesc, arg1 as off_t, arg2 as i32), + SYS_FSYNC => fs::do_fsync(arg0 as FileDesc), + SYS_FDATASYNC => fs::do_fdatasync(arg0 as FileDesc), + SYS_TRUNCATE => fs::do_truncate(arg0 as *const i8, arg1 as usize), + SYS_FTRUNCATE => fs::do_ftruncate(arg0 as FileDesc, arg1 as usize), + SYS_GETDENTS64 => fs::do_getdents64(arg0 as FileDesc, arg1 as *mut u8, arg2 as usize), + SYS_SYNC => fs::do_sync(), SYS_GETCWD => do_getcwd(arg0 as *mut u8, arg1 as usize), - SYS_CHDIR => do_chdir(arg0 as *mut i8), - SYS_RENAME => do_rename(arg0 as *const i8, arg1 as *const i8), - SYS_MKDIR => do_mkdir(arg0 as *const i8, arg1 as usize), - SYS_RMDIR => do_rmdir(arg0 as *const i8), - SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8), - SYS_UNLINK => do_unlink(arg0 as *const i8), - SYS_READLINK => do_readlink(arg0 as *const i8, arg1 as *mut u8, arg2 as usize), - SYS_SENDFILE => do_sendfile( + SYS_CHDIR => fs::do_chdir(arg0 as *mut i8), + SYS_RENAME => fs::do_rename(arg0 as *const i8, arg1 as *const i8), + SYS_MKDIR => fs::do_mkdir(arg0 as *const i8, arg1 as usize), + SYS_RMDIR => fs::do_rmdir(arg0 as *const i8), + SYS_LINK => fs::do_link(arg0 as *const i8, arg1 as *const i8), + SYS_UNLINK => fs::do_unlink(arg0 as *const i8), + SYS_READLINK => fs::do_readlink(arg0 as *const i8, arg1 as *mut u8, arg2 as usize), + SYS_SENDFILE => fs::do_sendfile( arg0 as FileDesc, arg1 as FileDesc, arg2 as *mut off_t, arg3 as usize, ), - SYS_FCNTL => do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64), - SYS_IOCTL => do_ioctl(arg0 as FileDesc, arg1 as u32, arg2 as *mut u8), + SYS_FCNTL => fs::do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64), + SYS_IOCTL => fs::do_ioctl(arg0 as FileDesc, arg1 as u32, arg2 as *mut u8), // IO multiplexing - SYS_SELECT => do_select( + SYS_SELECT => net::do_select( arg0 as c_int, arg1 as *mut libc::fd_set, arg2 as *mut libc::fd_set, arg3 as *mut libc::fd_set, arg4 as *const libc::timeval, ), - SYS_POLL => do_poll( + SYS_POLL => net::do_poll( arg0 as *mut libc::pollfd, arg1 as libc::nfds_t, arg2 as c_int, ), - SYS_EPOLL_CREATE => do_epoll_create(arg0 as c_int), - SYS_EPOLL_CREATE1 => do_epoll_create1(arg0 as c_int), - SYS_EPOLL_CTL => do_epoll_ctl( + SYS_EPOLL_CREATE => net::do_epoll_create(arg0 as c_int), + SYS_EPOLL_CREATE1 => net::do_epoll_create1(arg0 as c_int), + SYS_EPOLL_CTL => net::do_epoll_ctl( arg0 as c_int, arg1 as c_int, arg2 as c_int, arg3 as *const libc::epoll_event, ), - SYS_EPOLL_WAIT => do_epoll_wait( + SYS_EPOLL_WAIT => net::do_epoll_wait( arg0 as c_int, arg1 as *mut libc::epoll_event, arg2 as c_int, arg3 as c_int, ), - SYS_EPOLL_PWAIT => do_epoll_pwait( + SYS_EPOLL_PWAIT => net::do_epoll_pwait( arg0 as c_int, arg1 as *mut libc::epoll_event, arg2 as c_int, @@ -225,11 +222,11 @@ pub extern "C" fn dispatch_syscall( SYS_MPROTECT => do_mprotect(arg0 as usize, arg1 as usize, arg2 as u32), SYS_BRK => do_brk(arg0 as usize), - SYS_PIPE => do_pipe2(arg0 as *mut i32, 0), - SYS_PIPE2 => do_pipe2(arg0 as *mut i32, arg1 as u32), - SYS_DUP => do_dup(arg0 as FileDesc), - SYS_DUP2 => do_dup2(arg0 as FileDesc, arg1 as FileDesc), - SYS_DUP3 => do_dup3(arg0 as FileDesc, arg1 as FileDesc, arg2 as u32), + SYS_PIPE => fs::do_pipe2(arg0 as *mut i32, 0), + SYS_PIPE2 => fs::do_pipe2(arg0 as *mut i32, arg1 as u32), + SYS_DUP => fs::do_dup(arg0 as FileDesc), + SYS_DUP2 => fs::do_dup2(arg0 as FileDesc, arg1 as FileDesc), + SYS_DUP3 => fs::do_dup3(arg0 as FileDesc, arg1 as FileDesc, arg2 as u32), SYS_GETTIMEOFDAY => do_gettimeofday(arg0 as *mut timeval_t), SYS_CLOCK_GETTIME => do_clock_gettime(arg0 as clockid_t, arg1 as *mut timespec_t), @@ -362,12 +359,6 @@ fn print_syscall_timing() { } } -#[allow(non_camel_case_types)] -pub struct iovec_t { - base: *const c_void, - len: size_t, -} - /* * This Rust-version of fdop correspond to the C-version one in Occlum. * See /src/process/fdop.h. @@ -518,196 +509,6 @@ pub fn do_futex( } } -fn do_open(path: *const i8, flags: u32, mode: u32) -> Result { - 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 { - fs::do_close(fd)?; - Ok(0) -} - -fn do_read(fd: FileDesc, buf: *mut u8, size: usize) -> Result { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - fs::do_fsync(fd)?; - Ok(0) -} - -fn do_fdatasync(fd: FileDesc) -> Result { - fs::do_fdatasync(fd)?; - Ok(0) -} - -fn do_truncate(path: *const i8, len: usize) -> Result { - 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 { - fs::do_ftruncate(fd, len)?; - Ok(0) -} - -fn do_getdents64(fd: FileDesc, buf: *mut u8, buf_size: usize) -> Result { - 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 { - fs::do_sync()?; - Ok(0) -} - fn do_mmap( addr: usize, size: usize, @@ -817,32 +618,6 @@ fn do_getegid() -> Result { Ok(0) } -fn do_pipe2(fds_u: *mut i32, flags: u32) -> Result { - 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 { - let new_fd = fs::do_dup(old_fd)?; - Ok(new_fd as isize) -} - -fn do_dup2(old_fd: FileDesc, new_fd: FileDesc) -> Result { - 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 { - let new_fd = fs::do_dup3(old_fd, new_fd, flags)?; - Ok(new_fd as isize) -} - // TODO: handle tz: timezone_t fn do_gettimeofday(tv_u: *mut timeval_t) -> Result { check_mut_ptr(tv_u)?; @@ -921,101 +696,6 @@ fn do_getcwd(buf: *mut u8, size: usize) -> Result { Ok(buf as isize) } -fn do_chdir(path: *const i8) -> Result { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - let cmd = FcntlCmd::from_raw(cmd, arg)?; - fs::do_fcntl(fd, &cmd) -} - -fn do_ioctl(fd: FileDesc, cmd: u32, argp: *mut u8) -> Result { - 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 { let code = process::ArchPrctlCode::from_u32(code)?; check_mut_ptr(addr)?; @@ -1406,117 +1086,6 @@ fn do_socketpair( } } -fn do_select( - nfds: c_int, - readfds: *mut libc::fd_set, - writefds: *mut libc::fd_set, - exceptfds: *mut libc::fd_set, - timeout: *const libc::timeval, -) -> Result { - // 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 { - 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 { - if size <= 0 { - return_errno!(EINVAL, "size is not positive"); - } - do_epoll_create1(0) -} - -fn do_epoll_create1(flags: c_int) -> Result { - 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 { - 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 { - 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 { - info!("epoll_pwait"); - //TODO:add signal support - do_epoll_wait(epfd, events, maxevents, 0) -} - fn do_uname(name: *mut utsname_t) -> Result { check_mut_ptr(name)?; let name = unsafe { &mut *name }; @@ -1549,26 +1118,6 @@ fn do_prlimit( misc::do_prlimit(pid, resource, new_limit, old_limit).map(|_| 0) } -fn do_access(path: *const i8, mode: u32) -> Result { - 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 { - let dirfd = if dirfd >= 0 { - Some(dirfd as FileDesc) - } else if dirfd == AT_FDCWD { - None - } else { - return_errno!(EINVAL, "invalid dirfd"); - }; - let path = clone_cstring_safely(path)?.to_string_lossy().into_owned(); - let mode = AccessModes::from_u32(mode)?; - let flags = AccessFlags::from_u32(flags)?; - fs::do_faccessat(dirfd, &path, mode, flags).map(|_| 0) -} - // TODO: implement signals fn do_rt_sigaction() -> Result {