implement sys_sendfile

This commit is contained in:
WangRunji 2019-04-22 15:37:19 +08:00
parent f4dacdc01d
commit b99344d7f5
2 changed files with 124 additions and 48 deletions

@ -14,6 +14,7 @@ use self::inode_file::OpenOptions;
pub use self::pipe::Pipe; pub use self::pipe::Pipe;
pub use self::io_multiplexing::*; pub use self::io_multiplexing::*;
pub use self::access::{AccessModes, AccessFlags, AT_FDCWD, do_access, do_faccessat}; pub use self::access::{AccessModes, AccessFlags, AT_FDCWD, do_access, do_faccessat};
use std::mem::uninitialized;
mod file; mod file;
mod file_table; mod file_table;
@ -342,6 +343,56 @@ pub fn do_unlink(path: &str) -> Result<(), Error> {
Ok(()) Ok(())
} }
pub fn do_sendfile(
out_fd: FileDesc,
in_fd: FileDesc,
offset: Option<off_t>,
count: usize,
) -> Result<(usize, usize), Error> { // (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] = unsafe { uninitialized() };
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 Err(Error::new(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" { extern "C" {
fn ocall_sync() -> sgx_status_t; fn ocall_sync() -> sgx_status_t;
} }

@ -7,16 +7,16 @@
//! 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::{File, SocketFile, FileDesc, FileRef, AccessModes, AccessFlags, AT_FDCWD, FcntlCmd}; use fs::{AccessFlags, AccessModes, FcntlCmd, File, FileDesc, FileRef, SocketFile, AT_FDCWD};
use misc::{resource_t, rlimit_t, utsname_t};
use prelude::*; use prelude::*;
use process::{ChildProcessFilter, FileAction, pid_t, CloneFlags, FutexFlags, FutexOp}; use process::{pid_t, ChildProcessFilter, CloneFlags, FileAction, FutexFlags, FutexOp};
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::ptr; use std::ptr;
use time::timeval_t; use time::timeval_t;
use util::mem_util::from_user::*; use util::mem_util::from_user::*;
use vm::{VMAreaFlags, VMResizeOptions}; use vm::{VMAreaFlags, VMResizeOptions};
use {fs, process, std, vm}; use {fs, process, std, vm};
use misc::{utsname_t, resource_t, rlimit_t};
use super::*; use super::*;
@ -84,6 +84,12 @@ pub extern "C" fn dispatch_syscall(
SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8), SYS_LINK => do_link(arg0 as *const i8, arg1 as *const i8),
SYS_UNLINK => do_unlink(arg0 as *const i8), SYS_UNLINK => do_unlink(arg0 as *const i8),
SYS_READLINK => do_readlink(arg0 as *const i8, arg1 as *mut u8, arg2 as usize), SYS_READLINK => do_readlink(arg0 as *const i8, arg1 as *mut u8, arg2 as usize),
SYS_SENDFILE => do_sendfile(
arg0 as FileDesc,
arg1 as FileDesc,
arg2 as *mut off_t,
arg3 as usize,
),
SYS_FCNTL => do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64), SYS_FCNTL => do_fcntl(arg0 as FileDesc, arg1 as u32, arg2 as u64),
// IO multiplexing // IO multiplexing
@ -171,11 +177,7 @@ pub extern "C" fn dispatch_syscall(
arg3 as i32, arg3 as i32,
arg4 as usize, arg4 as usize,
), ),
SYS_MPROTECT => do_mprotect( SYS_MPROTECT => do_mprotect(arg0 as usize, arg1 as usize, arg2 as u32),
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 => do_pipe2(arg0 as *mut i32, 0),
@ -188,8 +190,12 @@ pub extern "C" fn dispatch_syscall(
SYS_UNAME => do_uname(arg0 as *mut utsname_t), SYS_UNAME => do_uname(arg0 as *mut utsname_t),
SYS_PRLIMIT64 => do_prlimit(arg0 as pid_t, arg1 as u32, arg2 as *const rlimit_t, arg3 as *mut rlimit_t), SYS_PRLIMIT64 => do_prlimit(
arg0 as pid_t,
arg1 as u32,
arg2 as *const rlimit_t,
arg3 as *mut rlimit_t,
),
// socket // socket
SYS_SOCKET => do_socket(arg0 as c_int, arg1 as c_int, arg2 as c_int), SYS_SOCKET => do_socket(arg0 as c_int, arg1 as c_int, arg2 as c_int),
@ -250,7 +256,7 @@ pub extern "C" fn dispatch_syscall(
_ => do_unknown(num, arg0, arg1, arg2, arg3, arg4, arg5), _ => do_unknown(num, arg0, arg1, arg2, arg3, arg4, arg5),
}; };
debug!("syscall return: {:?}", ret); info!("=> {:?}", ret);
match ret { match ret {
Ok(code) => code as isize, Ok(code) => code as isize,
@ -298,7 +304,9 @@ fn clone_file_actions_safely(fdop_ptr: *const FdOp) -> Result<Vec<FileAction>, E
FDOP_CLOSE => FileAction::Close(fdop.fd), FDOP_CLOSE => FileAction::Close(fdop.fd),
FDOP_DUP2 => FileAction::Dup2(fdop.srcfd, fdop.fd), FDOP_DUP2 => FileAction::Dup2(fdop.srcfd, fdop.fd),
FDOP_OPEN => FileAction::Open { FDOP_OPEN => FileAction::Open {
path: clone_cstring_safely(fdop.path)?.to_string_lossy().into_owned(), path: clone_cstring_safely(fdop.path)?
.to_string_lossy()
.into_owned(),
mode: fdop.mode, mode: fdop.mode,
oflag: fdop.oflag, oflag: fdop.oflag,
fd: fdop.fd, fd: fdop.fd,
@ -352,8 +360,7 @@ pub fn do_clone(
if flags.contains(CloneFlags::CLONE_PARENT_SETTID) { if flags.contains(CloneFlags::CLONE_PARENT_SETTID) {
check_mut_ptr(ptid)?; check_mut_ptr(ptid)?;
Some(ptid) Some(ptid)
} } else {
else {
None None
} }
}; };
@ -361,8 +368,7 @@ pub fn do_clone(
if flags.contains(CloneFlags::CLONE_CHILD_CLEARTID) { if flags.contains(CloneFlags::CLONE_CHILD_CLEARTID) {
check_mut_ptr(ctid)?; check_mut_ptr(ctid)?;
Some(ctid) Some(ctid)
} } else {
else {
None None
} }
}; };
@ -370,8 +376,7 @@ pub fn do_clone(
if flags.contains(CloneFlags::CLONE_SETTLS) { if flags.contains(CloneFlags::CLONE_SETTLS) {
check_mut_ptr(new_tls as *mut usize)?; check_mut_ptr(new_tls as *mut usize)?;
Some(new_tls) Some(new_tls)
} } else {
else {
None None
} }
}; };
@ -381,17 +386,11 @@ pub fn do_clone(
Ok(child_pid as isize) Ok(child_pid as isize)
} }
pub fn do_futex( pub fn do_futex(futex_addr: *const i32, futex_op: u32, futex_val: i32) -> Result<isize, Error> {
futex_addr: *const i32,
futex_op: u32,
futex_val: i32,
) -> Result<isize, Error> {
check_ptr(futex_addr)?; check_ptr(futex_addr)?;
let (futex_op, futex_flags) = process::futex_op_and_flags_from_u32(futex_op)?; let (futex_op, futex_flags) = process::futex_op_and_flags_from_u32(futex_op)?;
match futex_op { match futex_op {
FutexOp::FUTEX_WAIT => { FutexOp::FUTEX_WAIT => process::futex_wait(futex_addr, futex_val).map(|_| 0),
process::futex_wait(futex_addr, futex_val).map(|_| 0)
}
FutexOp::FUTEX_WAKE => { FutexOp::FUTEX_WAKE => {
let max_count = { let max_count = {
if futex_val < 0 { if futex_val < 0 {
@ -399,9 +398,8 @@ pub fn do_futex(
} }
futex_val as usize futex_val as usize
}; };
process::futex_wake(futex_addr, max_count) process::futex_wake(futex_addr, max_count).map(|count| count as isize)
.map(|count| count as isize) }
},
_ => errno!(ENOSYS, "the futex operation is not supported"), _ => errno!(ENOSYS, "the futex operation is not supported"),
} }
} }
@ -627,11 +625,7 @@ fn do_mremap(
Ok(ret_addr as isize) Ok(ret_addr as isize)
} }
fn do_mprotect( fn do_mprotect(addr: usize, len: usize, prot: u32) -> Result<isize, Error> {
addr: usize,
len: usize,
prot: u32,
) -> Result<isize, Error> {
// TODO: implement it // TODO: implement it
Ok(0) Ok(0)
} }
@ -710,7 +704,6 @@ fn do_getegid() -> Result<isize, Error> {
Ok(0) Ok(0)
} }
fn do_pipe2(fds_u: *mut i32, flags: u32) -> Result<isize, Error> { fn do_pipe2(fds_u: *mut i32, flags: u32) -> Result<isize, Error> {
check_mut_array(fds_u, 2)?; check_mut_array(fds_u, 2)?;
// TODO: how to deal with open flags??? // TODO: how to deal with open flags???
@ -761,7 +754,15 @@ fn do_exit(status: i32) -> ! {
} }
} }
fn do_unknown(num: u32, arg0: isize, arg1: isize, arg2: isize, arg3: isize, arg4: isize, arg5: isize) -> Result<isize, Error> { fn do_unknown(
num: u32,
arg0: isize,
arg1: isize,
arg2: isize,
arg3: isize,
arg4: isize,
arg5: isize,
) -> Result<isize, Error> {
warn!( warn!(
"unknown or unsupported syscall (# = {}): {:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:#x}", "unknown or unsupported syscall (# = {}): {:#x}, {:#x}, {:#x}, {:#x}, {:#x}, {:#x}",
num, arg0, arg1, arg2, arg3, arg4, arg5 num, arg0, arg1, arg2, arg3, arg4, arg5
@ -841,6 +842,28 @@ fn do_readlink(path: *const i8, buf: *mut u8, size: usize) -> Result<isize, Erro
Ok(len as isize) Ok(len as isize)
} }
fn do_sendfile(
out_fd: FileDesc,
in_fd: FileDesc,
offset_ptr: *mut off_t,
count: usize,
) -> Result<isize, Error> {
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, Error> { fn do_fcntl(fd: FileDesc, cmd: u32, arg: u64) -> Result<isize, Error> {
let cmd = FcntlCmd::from_raw(cmd, arg)?; let cmd = FcntlCmd::from_raw(cmd, arg)?;
fs::do_fcntl(fd, &cmd) fs::do_fcntl(fd, &cmd)
@ -1037,11 +1060,14 @@ fn do_select(
readfds: *mut libc::fd_set, readfds: *mut libc::fd_set,
writefds: *mut libc::fd_set, writefds: *mut libc::fd_set,
exceptfds: *mut libc::fd_set, exceptfds: *mut libc::fd_set,
timeout: *const libc::timeval timeout: *const libc::timeval,
) -> Result<isize, Error> { ) -> Result<isize, Error> {
// check arguments // check arguments
if nfds < 0 || nfds >= libc::FD_SETSIZE as c_int { if nfds < 0 || nfds >= libc::FD_SETSIZE as c_int {
return Err(Error::new(EINVAL, "nfds is negative or exceeds the resource limit")); return Err(Error::new(
EINVAL,
"nfds is negative or exceeds the resource limit",
));
} }
let nfds = nfds as usize; let nfds = nfds as usize;
@ -1078,11 +1104,7 @@ fn do_select(
Ok(n as isize) Ok(n as isize)
} }
fn do_poll( fn do_poll(fds: *mut libc::pollfd, nfds: libc::nfds_t, timeout: c_int) -> Result<isize, Error> {
fds: *mut libc::pollfd,
nfds: libc::nfds_t,
timeout: c_int,
) -> Result<isize, Error> {
check_mut_array(fds, nfds as usize)?; check_mut_array(fds, nfds as usize)?;
let polls = unsafe { std::slice::from_raw_parts_mut(fds, nfds as usize) }; let polls = unsafe { std::slice::from_raw_parts_mut(fds, nfds as usize) };
@ -1153,14 +1175,18 @@ fn do_uname(name: *mut utsname_t) -> Result<isize, Error> {
misc::do_uname(name).map(|_| 0) misc::do_uname(name).map(|_| 0)
} }
fn do_prlimit(pid: pid_t, resource: u32, new_limit: *const rlimit_t, old_limit: *mut rlimit_t) -> Result<isize, Error> { fn do_prlimit(
pid: pid_t,
resource: u32,
new_limit: *const rlimit_t,
old_limit: *mut rlimit_t,
) -> Result<isize, Error> {
let resource = resource_t::from_u32(resource)?; let resource = resource_t::from_u32(resource)?;
let new_limit = { let new_limit = {
if new_limit != ptr::null() { if new_limit != ptr::null() {
check_ptr(new_limit)?; check_ptr(new_limit)?;
Some(unsafe { &*new_limit }) Some(unsafe { &*new_limit })
} } else {
else {
None None
} }
}; };
@ -1168,8 +1194,7 @@ fn do_prlimit(pid: pid_t, resource: u32, new_limit: *const rlimit_t, old_limit:
if old_limit != ptr::null_mut() { if old_limit != ptr::null_mut() {
check_mut_ptr(old_limit)?; check_mut_ptr(old_limit)?;
Some(unsafe { &mut *old_limit }) Some(unsafe { &mut *old_limit })
} } else {
else {
None None
} }
}; };