-use crate::io::{Error as IoError, Result as IoResult};
+use crate::cmp;
+use crate::io::{Error as IoError, IoSlice, IoSliceMut, Result as IoResult};
use crate::time::Duration;
pub(crate) mod alloc;
use self::raw::*;
/// Usercall `read`. See the ABI documentation for more information.
+///
+/// This will do a single `read` usercall and scatter the read data among
+/// `bufs`. To read to a single buffer, just pass a slice of length one.
#[unstable(feature = "sgx_platform", issue = "56975")]
-pub fn read(fd: Fd, buf: &mut [u8]) -> IoResult<usize> {
+pub fn read(fd: Fd, bufs: &mut [IoSliceMut<'_>]) -> IoResult<usize> {
unsafe {
- let mut userbuf = alloc::User::<[u8]>::uninitialized(buf.len());
- let len = raw::read(fd, userbuf.as_mut_ptr(), userbuf.len()).from_sgx_result()?;
- userbuf[..len].copy_to_enclave(&mut buf[..len]);
- Ok(len)
+ let total_len = bufs.iter().fold(0usize, |sum, buf| sum.saturating_add(buf.len()));
+ let mut userbuf = alloc::User::<[u8]>::uninitialized(total_len);
+ let ret_len = raw::read(fd, userbuf.as_mut_ptr(), userbuf.len()).from_sgx_result()?;
+ let userbuf = &userbuf[..ret_len];
+ let mut index = 0;
+ for buf in bufs {
+ let end = cmp::min(index + buf.len(), userbuf.len());
+ if let Some(buflen) = end.checked_sub(index) {
+ userbuf[index..end].copy_to_enclave(&mut buf[..buflen]);
+ index += buf.len();
+ } else {
+ break;
+ }
+ }
+ Ok(userbuf.len())
}
}
}
/// Usercall `write`. See the ABI documentation for more information.
+///
+/// This will do a single `write` usercall and gather the written data from
+/// `bufs`. To write from a single buffer, just pass a slice of length one.
#[unstable(feature = "sgx_platform", issue = "56975")]
-pub fn write(fd: Fd, buf: &[u8]) -> IoResult<usize> {
+pub fn write(fd: Fd, bufs: &[IoSlice<'_>]) -> IoResult<usize> {
unsafe {
- let userbuf = alloc::User::new_from_enclave(buf);
+ let total_len = bufs.iter().fold(0usize, |sum, buf| sum.saturating_add(buf.len()));
+ let mut userbuf = alloc::User::<[u8]>::uninitialized(total_len);
+ let mut index = 0;
+ for buf in bufs {
+ let end = cmp::min(index + buf.len(), userbuf.len());
+ if let Some(buflen) = end.checked_sub(index) {
+ userbuf[index..end].copy_from_enclave(&buf[..buflen]);
+ index += buf.len();
+ } else {
+ break;
+ }
+ }
raw::write(fd, userbuf.as_ptr(), userbuf.len()).from_sgx_result()
}
}
unsafe {
let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
let mut local = alloc::User::<ByteBuffer>::uninitialized();
- let fd = raw::bind_stream(
- addr_user.as_ptr(),
- addr_user.len(),
- local.as_raw_mut_ptr()
- ).from_sgx_result()?;
+ let fd = raw::bind_stream(addr_user.as_ptr(), addr_user.len(), local.as_raw_mut_ptr())
+ .from_sgx_result()?;
let local = string_from_bytebuffer(&local, "bind_stream", "local_addr");
Ok((fd, local))
}
unsafe {
let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized();
let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); // FIXME: can this be done
- // without forcing coercion?
+ // without forcing coercion?
let (local, peer) = (buf_it.next().unwrap(), buf_it.next().unwrap());
- let fd = raw::accept_stream(
- fd,
- local.as_raw_mut_ptr(),
- peer.as_raw_mut_ptr()
- ).from_sgx_result()?;
+ let fd = raw::accept_stream(fd, local.as_raw_mut_ptr(), peer.as_raw_mut_ptr())
+ .from_sgx_result()?;
let local = string_from_bytebuffer(&local, "accept_stream", "local_addr");
let peer = string_from_bytebuffer(&peer, "accept_stream", "peer_addr");
Ok((fd, local, peer))
let addr_user = alloc::User::new_from_enclave(addr.as_bytes());
let mut bufs = alloc::User::<[ByteBuffer; 2]>::uninitialized();
let mut buf_it = alloc::UserRef::iter_mut(&mut *bufs); // FIXME: can this be done
- // without forcing coercion?
+ // without forcing coercion?
let (local, peer) = (buf_it.next().unwrap(), buf_it.next().unwrap());
let fd = raw::connect_stream(
addr_user.as_ptr(),
addr_user.len(),
local.as_raw_mut_ptr(),
- peer.as_raw_mut_ptr()
- ).from_sgx_result()?;
+ peer.as_raw_mut_ptr(),
+ )
+ .from_sgx_result()?;
let local = string_from_bytebuffer(&local, "connect_stream", "local_addr");
let peer = string_from_bytebuffer(&peer, "connect_stream", "peer_addr");
Ok((fd, local, peer))
fn check_os_error(err: Result) -> i32 {
// FIXME: not sure how to make sure all variants of Error are covered
- if err == Error::NotFound as _ ||
- err == Error::PermissionDenied as _ ||
- err == Error::ConnectionRefused as _ ||
- err == Error::ConnectionReset as _ ||
- err == Error::ConnectionAborted as _ ||
- err == Error::NotConnected as _ ||
- err == Error::AddrInUse as _ ||
- err == Error::AddrNotAvailable as _ ||
- err == Error::BrokenPipe as _ ||
- err == Error::AlreadyExists as _ ||
- err == Error::WouldBlock as _ ||
- err == Error::InvalidInput as _ ||
- err == Error::InvalidData as _ ||
- err == Error::TimedOut as _ ||
- err == Error::WriteZero as _ ||
- err == Error::Interrupted as _ ||
- err == Error::Other as _ ||
- err == Error::UnexpectedEof as _ ||
- ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&err)
+ if err == Error::NotFound as _
+ || err == Error::PermissionDenied as _
+ || err == Error::ConnectionRefused as _
+ || err == Error::ConnectionReset as _
+ || err == Error::ConnectionAborted as _
+ || err == Error::NotConnected as _
+ || err == Error::AddrInUse as _
+ || err == Error::AddrNotAvailable as _
+ || err == Error::BrokenPipe as _
+ || err == Error::AlreadyExists as _
+ || err == Error::WouldBlock as _
+ || err == Error::InvalidInput as _
+ || err == Error::InvalidData as _
+ || err == Error::TimedOut as _
+ || err == Error::WriteZero as _
+ || err == Error::Interrupted as _
+ || err == Error::Other as _
+ || err == Error::UnexpectedEof as _
+ || ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&err)
{
err
} else {