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