use core::result;
use derive_new::new;
use ioctls::ioctl;
use log::*;
use std::{
collections::HashSet,
fmt::Display,
};
use crate::{
Event,
EventSources,
NtSyncFlags,
error::Error,
};
pub(crate) type Result<T> = result::Result<T, Error>;
pub(crate) type AlertDescriptor = u32;
#[repr(transparent)]
#[derive(Debug, new, Clone, Copy, PartialEq, PartialOrd, Ord, Eq, Default)]
pub struct OwnerId(u32);
#[cfg(feature = "random")]
impl OwnerId {
pub fn random() -> Self {
OwnerId(rand::random::<u32>().clamp(1, u32::MAX))
}
}
impl Display for OwnerId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
#[repr(C)]
#[derive(Debug, new, Default)]
pub struct SemaphoreArgs {
#[new(value = "0")]
pub count: u32,
pub max: u32,
}
#[cfg(feature = "unstable_mutex")]
#[repr(C)]
#[derive(Debug, new, Default)]
pub struct MutexArgs {
owner: OwnerId,
#[new(value = "0")]
count: libc::__u32,
}
#[repr(C)]
#[derive(Debug, new, Default)]
pub struct EventStatus {
signaled: libc::__u32,
manual: libc::__u32,
}
impl EventStatus {
pub fn manual_signal(&self) -> bool {
self.manual == 1
}
pub fn auto_signal(&self) -> bool {
self.signaled == 1
}
}
#[repr(C)]
#[derive(Debug)]
pub struct WaitArgs {
timeout: u64,
objs: *const u64,
count: u32,
owner: u32,
index: u32,
alert: AlertDescriptor,
flags: u32,
pad: u32,
}
impl WaitArgs {
pub(crate) fn new(timeout: u64, eventssources: HashSet<EventSources>, alert: Option<Event>, owner: Option<OwnerId>, flags: NtSyncFlags) -> Result<Self> {
let mut ids = Vec::new();
let alertid = alert
.unwrap_or(Event {
id: 0,
})
.id;
for source in eventssources {
match source {
EventSources::Event(event) => {
if alertid != 0 && alertid == event.id {
return Err(Error::DuplicateEvent);
}
ids.push(event.id as u64)
},
EventSources::Semaphore(semaphore) => ids.push(semaphore.id as u64),
#[cfg(feature = "unstable_mutex")]
EventSources::Mutex(mutex) => {
if owner.is_none_or(|val| val.0 == 0) {
error!("Invalid Owner. Owner must be an non Zero value");
return Err(Error::InvalidValue);
}
ids.push(mutex.id as u64);
},
}
}
Ok(Self {
timeout,
objs: ids.as_ptr(),
count: ids.len() as u32,
owner: owner.unwrap_or_default().0,
index: 0,
alert: 0,
flags: 0,
pad: 0,
})
}
}
ioctl!(write ntsync_create_sem with b'N', 0x80; SemaphoreArgs);
ioctl!(read ntsync_sem_read with b'N', 0x8b; SemaphoreArgs);
ioctl!(readwrite ntsync_sem_release with b'N', 0x81; u32);
#[cfg(feature = "unstable_mutex")]
ioctl!(write ntsync_create_mutex with b'N', 0x84; MutexArgs);
#[cfg(feature = "unstable_mutex")]
ioctl!(readwrite ntsync_mutex_unlock with b'N', 0x85; MutexArgs);
#[cfg(feature = "unstable_mutex")]
ioctl!(write ntsync_mutex_kill with b'N', 0x86; u32);
#[cfg(feature = "unstable_mutex")]
ioctl!(read ntsync_mutex_read with b'N', 0x8c; MutexArgs);
ioctl!(write ntsync_create_event with b'N', 0x87; EventStatus);
ioctl!(read ntsync_event_set with b'N', 0x88; u32);
ioctl!(read ntsync_event_reset with b'N', 0x89; u32);
ioctl!(read ntsync_event_pulse with b'N', 0x8a; u32);
ioctl!(read ntsync_event_read with b'N', 0x8d; EventStatus);
ioctl!(readwrite ntsync_wait_any with b'N', 0x82; WaitArgs);
ioctl!(readwrite ntsync_wait_all with b'N', 0x83; WaitArgs);