Add lseek

This commit is contained in:
Tate, Hongliang Tian 2018-11-30 15:01:52 +08:00
parent f2ebc5c330
commit 10e3da87cc
6 changed files with 152 additions and 13 deletions

@ -3,14 +3,13 @@ use {std};
use std::{fmt};
use std::sgxfs as fs_impl;
use std::io::{Read, Write, Seek, SeekFrom};
pub trait File : Debug + Sync + Send {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error>;
fn write(&self, buf: &[u8]) -> Result<usize, Error>;
fn readv<'a, 'b>(&self, bufs: &'a mut [&'b mut [u8]]) -> Result<usize, Error>;
fn writev<'a, 'b>(&self, bufs: &'a [&'b [u8]]) -> Result<usize, Error>;
//pub seek(&mut self, ) -> Result<usize, Error>;
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error>;
}
pub type FileRef = Arc<Box<File>>;
@ -23,9 +22,14 @@ pub struct SgxFile {
impl SgxFile {
pub fn new(file: Arc<SgxMutex<fs_impl::SgxFile>>,
is_readable: bool, is_writable: bool, is_append: bool) -> SgxFile
is_readable: bool, is_writable: bool, is_append: bool)
-> Result<SgxFile, Error>
{
SgxFile {
if !is_readable && !is_writable {
return Err(Error::new(Errno::EINVAL, "Invalid permissions"));
}
Ok(SgxFile {
inner: SgxMutex::new(SgxFileInner {
pos: 0 as usize,
file: file,
@ -33,7 +37,7 @@ impl SgxFile {
is_writable,
is_append,
}),
}
})
}
}
@ -61,6 +65,12 @@ impl File for SgxFile {
let inner = inner_guard.borrow_mut();
inner.writev(bufs)
}
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> {
let mut inner_guard = self.inner.lock().unwrap();
let inner = inner_guard.borrow_mut();
inner.seek(pos)
}
}
#[derive(Clone)]
@ -76,10 +86,18 @@ struct SgxFileInner {
impl SgxFileInner {
pub fn write(&mut self, buf: &[u8]) -> Result<usize, Error> {
if !self.is_writable {
return Err(Error::new(Errno::EINVAL, "File not writable"));
}
let mut file_guard = self.file.lock().unwrap();
let file = file_guard.borrow_mut();
let seek_pos = SeekFrom::Start(self.pos as u64);
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| Error::new(Errno::EINVAL, "Failed to seek to a position"))?;
@ -89,11 +107,17 @@ impl SgxFileInner {
|e| Error::new(Errno::EINVAL, "Failed to write"))?
};
self.pos += write_len;
if !self.is_append {
self.pos += write_len;
}
Ok(write_len)
}
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
if !self.is_readable {
return Err(Error::new(Errno::EINVAL, "File not readable"));
}
let mut file_guard = self.file.lock().unwrap();
let file = file_guard.borrow_mut();
@ -110,11 +134,50 @@ impl SgxFileInner {
Ok(read_len)
}
pub fn writev<'a, 'b>(&mut self, bufs: &'a [&'b [u8]]) -> Result<usize, Error> {
pub fn seek(&mut self, pos: SeekFrom) -> Result<off_t, Error> {
let mut file_guard = self.file.lock().unwrap();
let file = file_guard.borrow_mut();
let seek_pos = SeekFrom::Start(self.pos as u64);
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 Err(Error::new(Errno::EINVAL,
"Invalid seek position"));
}
SeekFrom::Start((self.pos - backward_offset) as u64)
}
}
};
self.pos = file.seek(pos).map_err(
|e| Error::new(Errno::EINVAL, "Failed to seek to a position"))? as usize;
Ok(self.pos as off_t)
}
pub fn writev<'a, 'b>(&mut self, bufs: &'a [&'b [u8]]) -> Result<usize, Error> {
if !self.is_writable {
return Err(Error::new(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| Error::new(Errno::EINVAL, "Failed to seek to a position"))?;
@ -143,6 +206,10 @@ impl SgxFileInner {
}
fn readv<'a, 'b>(&mut self, bufs: &'a mut [&'b mut [u8]]) -> Result<usize, Error> {
if !self.is_readable {
return Err(Error::new(Errno::EINVAL, "File not readable"));
}
let mut file_guard = self.file.lock().unwrap();
let file = file_guard.borrow_mut();
@ -233,7 +300,11 @@ impl File for StdoutFile {
}
fn readv<'a, 'b>(&self, bufs: &'a mut [&'b mut [u8]]) -> Result<usize, Error> {
Err(Error::new(Errno::EBADF, "Stdout does not support reading"))
Err(Error::new(Errno::EBADF, "Stdout does not support read"))
}
fn seek(&self, seek_pos: SeekFrom) -> Result<off_t, Error> {
Err(Error::new(Errno::ESPIPE, "Stdout does not support seek"))
}
}
@ -268,7 +339,11 @@ impl File for StdinFile {
}
fn write(&self, buf: &[u8]) -> Result<usize, Error> {
Err(Error::new(Errno::EBADF, "Stdin does not support reading"))
Err(Error::new(Errno::EBADF, "Stdin does not support write"))
}
fn seek(&self, pos: SeekFrom) -> Result<off_t, Error> {
Err(Error::new(Errno::ESPIPE, "Stdin does not support seek"))
}
fn readv<'a, 'b>(&self, bufs: &'a mut [&'b mut [u8]]) -> Result<usize, Error> {

@ -12,6 +12,13 @@ pub const O_CREAT : u32 = 0x00000040;
pub const O_TRUNC : u32 = 0x00000200;
pub const O_APPEND : u32 = 0x00000400;
// TODO: use the type defined in Rust libc.
//
// However, off_t is defined as i64 in the current Rust SGX SDK, which is
// wrong (see issue https://github.com/baidu/rust-sgx-sdk/issues/46)
#[allow(non_camel_case_types)]
pub type off_t = i64;
pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> {
let open_options = {
let mut open_options = fs_impl::OpenOptions::new();
@ -29,6 +36,7 @@ pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> {
let mut sgx_file = {
let key : sgx_key_128bit_t = [0 as uint8_t; 16];
// TODO: what if two processes open the same underlying SGX file?
let sgx_file = open_options.open_ex(path, &key)
.map_err(|e| (Errno::ENOENT, "Failed to open the SGX-protected file") )?;
Arc::new(SgxMutex::new(sgx_file))
@ -38,7 +46,7 @@ pub fn do_open(path: &str, flags: u32, mode: u32) -> Result<FileDesc, Error> {
let is_writable = (flags & O_WRONLY != 0) || (flags & O_RDWR != 0);
let is_append = (flags & O_APPEND != 0);
let file_ref : Arc<Box<File>> = Arc::new(Box::new(
SgxFile::new(sgx_file, is_readable, is_writable, is_append)));
SgxFile::new(sgx_file, is_readable, is_writable, is_append)?));
let current_ref = process::get_current();
let mut current_process = current_ref.lock().unwrap();
@ -79,6 +87,14 @@ pub fn do_readv<'a, 'b>(fd: FileDesc, bufs: &'a mut [&'b mut [u8]]) -> Result<us
file_ref.readv(bufs)
}
pub fn do_lseek<'a, 'b>(fd: FileDesc, offset: SeekFrom) -> Result<off_t, Error> {
let current_ref = process::get_current();
let current_process = current_ref.lock().unwrap();
let file_ref = current_process.file_table.get(fd)
.ok_or_else(|| Error::new(Errno::EBADF, "Invalid file descriptor [do_lseek]"))?;
file_ref.seek(offset)
}
pub fn do_close(fd: FileDesc) -> Result<(), Error> {
let current_ref = process::get_current();
let mut current_process = current_ref.lock().unwrap();

@ -15,6 +15,9 @@ pub use std::vec::Vec;
pub use std::string::{String};
pub use std::collections::{HashMap, VecDeque};
pub use std::fmt::{Debug, Display};
pub use std::io::{Read, Write, Seek, SeekFrom};
pub use errno::Error as Error;
pub use errno::Errno;
pub use fs::off_t;

@ -16,6 +16,7 @@ extern ssize_t occlum_read(int fd, void* buf, size_t size);
extern ssize_t occlum_write(int fd, const void* buf, size_t size);
extern ssize_t occlum_readv(int fd, struct iovec* iov, int count);
extern ssize_t occlum_writev(int fd, const struct iovec* iov, int count);
extern off_t occlum_lseek(int fd, off_t offset, int whence);
extern int occlum_spawn(int* child_pid, const char* path,
const char** argv,
const char** envp);

@ -11,7 +11,6 @@ pub struct iovec_t {
len: size_t,
}
fn check_ptr_from_user<T>(user_ptr: *const T) -> Result<(), Error> {
Ok(())
}
@ -133,6 +132,33 @@ fn do_readv(fd: c_int, iov: *mut iovec_t, count: c_int)
}
pub fn do_lseek(fd: c_int, offset: off_t, whence: c_int) -> Result<off_t, Error>
{
let fd = fd as file_table::FileDesc;
let seek_from = match whence {
0 => { // SEEK_SET
if offset < 0 {
return Err(Error::new(Errno::EINVAL, "Invalid offset"));
}
SeekFrom::Start(offset as u64)
}
1 => { // SEEK_CUR
SeekFrom::Current(offset)
}
2 => { // SEEK_END
SeekFrom::End(offset)
}
_ => {
return Err(Error::new(Errno::EINVAL, "Invalid whence"));
}
};
fs::do_lseek(fd, seek_from)
}
#[no_mangle]
pub extern "C" fn occlum_open(path_buf: * const c_char, flags: c_int, mode: c_int) -> c_int {
let path = unsafe {
@ -208,6 +234,17 @@ pub extern "C" fn occlum_writev(fd: c_int, iov: * const iovec_t, count: c_int) -
}
}
#[no_mangle]
pub extern "C" fn occlum_lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t {
match do_lseek(fd, offset, whence) {
Ok(ret) => {
ret
},
Err(e) => {
-1 as off_t // this special value indicates error
}
}
}
#[no_mangle]
pub extern "C" fn occlum_getpid() -> c_uint

@ -54,6 +54,13 @@ long dispatch_syscall(int num, long arg0, long arg1, long arg2, long arg3, long
ret = occlum_readv(fd, iov, count);
break;
}
case SYS_lseek: {
DECL_SYSCALL_ARG(int, fd, arg0);
DECL_SYSCALL_ARG(off_t, offset, arg1);
DECL_SYSCALL_ARG(int, whence, arg2);
ret = occlum_lseek(fd, offset, whence);
break;
}
case SYS_spawn: {
DECL_SYSCALL_ARG(int*, child_pid, arg0);
DECL_SYSCALL_ARG(const char*, path, arg1);