summaryrefslogtreecommitdiff
path: root/crates/windows-kernel-rs/src/user_ptr.rs
diff options
context:
space:
mode:
authorFuwn <[email protected]>2022-01-03 03:20:12 -0800
committerFuwn <[email protected]>2022-01-03 03:20:12 -0800
commit85db2b507f3f69b32811c54a89d9ac7bbbc46121 (patch)
tree2efd66da452f8a6a2cc6c91584c925f237506ddf /crates/windows-kernel-rs/src/user_ptr.rs
downloaddriver-85db2b507f3f69b32811c54a89d9ac7bbbc46121.tar.xz
driver-85db2b507f3f69b32811c54a89d9ac7bbbc46121.zip
feat(driver): commit primer
Diffstat (limited to 'crates/windows-kernel-rs/src/user_ptr.rs')
-rw-r--r--crates/windows-kernel-rs/src/user_ptr.rs172
1 files changed, 172 insertions, 0 deletions
diff --git a/crates/windows-kernel-rs/src/user_ptr.rs b/crates/windows-kernel-rs/src/user_ptr.rs
new file mode 100644
index 0000000..54dcb58
--- /dev/null
+++ b/crates/windows-kernel-rs/src/user_ptr.rs
@@ -0,0 +1,172 @@
+use crate::error::Error;
+
+pub enum UserPtr {
+ Buffered {
+ ptr: *mut cty::c_void,
+ read_size: usize,
+ write_size: usize,
+ },
+ Direct {
+ read_ptr: *const cty::c_void,
+ write_ptr: *mut cty::c_void,
+ read_size: usize,
+ write_size: usize,
+ },
+ Neither,
+}
+
+impl UserPtr {
+ pub unsafe fn new_buffered(ptr: *mut cty::c_void, read_size: usize, write_size: usize) -> Self {
+ Self::Buffered {
+ ptr,
+ read_size,
+ write_size,
+ }
+ }
+
+ pub unsafe fn new_direct(
+ read_ptr: *const cty::c_void,
+ write_ptr: *mut cty::c_void,
+ read_size: usize,
+ write_size: usize,
+ ) -> Self {
+ Self::Direct {
+ read_ptr,
+ write_ptr,
+ read_size,
+ write_size,
+ }
+ }
+
+ pub unsafe fn new_neither() -> Self { Self::Neither }
+
+ pub fn read_size(&self) -> usize {
+ match self {
+ Self::Buffered {
+ read_size, ..
+ } => *read_size,
+ Self::Direct {
+ read_size, ..
+ } => *read_size,
+ Self::Neither => 0,
+ }
+ }
+
+ pub fn write_size(&self) -> usize {
+ match self {
+ Self::Buffered {
+ write_size, ..
+ } => *write_size,
+ Self::Direct {
+ write_size, ..
+ } => *write_size,
+ Self::Neither => 0,
+ }
+ }
+
+ pub fn as_slice(&self) -> &[u8] {
+ let (ptr, size) = match self {
+ Self::Buffered {
+ ptr,
+ read_size,
+ ..
+ } => (*ptr as _, *read_size),
+ Self::Direct {
+ read_ptr,
+ read_size,
+ ..
+ } => (*read_ptr, *read_size),
+ Self::Neither => (core::ptr::null(), 0),
+ };
+
+ if ptr.is_null() || size == 0 {
+ &[]
+ } else {
+ unsafe { core::slice::from_raw_parts(ptr as *const u8, size) }
+ }
+ }
+
+ pub fn as_mut_slice(&mut self) -> &mut [u8] {
+ let (ptr, size) = match self {
+ Self::Buffered {
+ ptr,
+ write_size,
+ ..
+ } => (*ptr, *write_size),
+ Self::Direct {
+ write_ptr,
+ write_size,
+ ..
+ } => (*write_ptr, *write_size),
+ Self::Neither => (core::ptr::null_mut(), 0),
+ };
+
+ if ptr.is_null() || size == 0 {
+ &mut []
+ } else {
+ unsafe { core::slice::from_raw_parts_mut(ptr as *mut u8, size) }
+ }
+ }
+
+ pub fn read<T: Copy + Default>(&self) -> Result<T, Error> {
+ let (ptr, size) = match self {
+ Self::Buffered {
+ ptr,
+ read_size,
+ ..
+ } => (*ptr as _, *read_size),
+ Self::Direct {
+ read_ptr,
+ read_size,
+ ..
+ } => (*read_ptr, *read_size),
+ Self::Neither => (core::ptr::null(), 0),
+ };
+
+ if ptr.is_null() || size == 0 {
+ return Err(Error::INVALID_PARAMETER);
+ }
+
+ if core::mem::size_of::<T>() > size {
+ return Err(Error::INVALID_USER_BUFFER);
+ }
+
+ let mut obj = T::default();
+
+ unsafe {
+ core::ptr::copy_nonoverlapping(ptr as _, &mut obj, 1);
+ }
+
+ Ok(obj)
+ }
+
+ pub fn write<T: Copy>(&mut self, obj: &T) -> Result<(), Error> {
+ let (ptr, size) = match self {
+ Self::Buffered {
+ ptr,
+ write_size,
+ ..
+ } => (*ptr, *write_size),
+ Self::Direct {
+ write_ptr,
+ write_size,
+ ..
+ } => (*write_ptr, *write_size),
+ Self::Neither => (core::ptr::null_mut(), 0),
+ };
+
+ if ptr.is_null() || size == 0 {
+ return Err(Error::INVALID_PARAMETER);
+ }
+
+ if core::mem::size_of::<T>() > size {
+ return Err(Error::INVALID_USER_BUFFER);
+ }
+
+ unsafe {
+ core::ptr::copy_nonoverlapping(obj, ptr as _, 1);
+ }
+
+ Ok(())
+ }
+}