use alloc::vec;
use alloc::vec::Vec;
use core::u32;
use crate::bindings;
use crate::c_types;
use crate::error;
extern "C" {
fn access_ok_helper(addr: *const c_types::c_void, len: c_types::c_ulong) -> c_types::c_int;
}
pub struct UserSlicePtr(*mut c_types::c_void, usize);
impl UserSlicePtr {
pub(crate) unsafe fn new(
ptr: *mut c_types::c_void,
length: usize,
) -> error::KernelResult<UserSlicePtr> {
if access_ok_helper(ptr, length as c_types::c_ulong) == 0 {
return Err(error::Error::EFAULT);
}
Ok(UserSlicePtr(ptr, length))
}
pub fn read_all(self) -> error::KernelResult<Vec<u8>> {
self.reader().read_all()
}
pub fn reader(self) -> UserSlicePtrReader {
UserSlicePtrReader(self.0, self.1)
}
pub fn write_all(self, data: &[u8]) -> error::KernelResult<()> {
self.writer().write(data)
}
pub fn writer(self) -> UserSlicePtrWriter {
UserSlicePtrWriter(self.0, self.1)
}
}
pub struct UserSlicePtrReader(*mut c_types::c_void, usize);
impl UserSlicePtrReader {
pub fn len(&self) -> usize {
self.1
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn read_all(&mut self) -> error::KernelResult<Vec<u8>> {
let mut data = vec![0; self.1];
self.read(&mut data)?;
Ok(data)
}
pub fn read(&mut self, data: &mut [u8]) -> error::KernelResult<()> {
if data.len() > self.1 || data.len() > u32::MAX as usize {
return Err(error::Error::EFAULT);
}
let res = unsafe {
bindings::_copy_from_user(
data.as_mut_ptr() as *mut c_types::c_void,
self.0,
data.len() as _,
)
};
if res != 0 {
return Err(error::Error::EFAULT);
}
self.0 = self.0.wrapping_add(data.len());
self.1 -= data.len();
Ok(())
}
}
pub struct UserSlicePtrWriter(*mut c_types::c_void, usize);
impl UserSlicePtrWriter {
pub fn len(&self) -> usize {
self.1
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn write(&mut self, data: &[u8]) -> error::KernelResult<()> {
if data.len() > self.1 || data.len() > u32::MAX as usize {
return Err(error::Error::EFAULT);
}
let res = unsafe {
bindings::_copy_to_user(
self.0,
data.as_ptr() as *const c_types::c_void,
data.len() as _,
)
};
if res != 0 {
return Err(error::Error::EFAULT);
}
self.0 = self.0.wrapping_add(data.len());
self.1 -= data.len();
Ok(())
}
}