use super::*;
use std::sync::{
atomic::{AtomicBool, Ordering},
Weak,
};
#[doc(hidden)]
pub struct AuditOwnership {
device: ObjectIdentifier,
reporters: Vec<ObjectIdentifier>,
association: Option<Arc<crate::audit::TargetAuditAssociation>>,
active: AtomicBool,
}
impl AuditOwnership {
pub fn for_source(device: ObjectIdentifier, reporter: ObjectIdentifier) -> Arc<Self> {
Arc::new(Self {
device,
reporters: vec![reporter],
association: None,
active: AtomicBool::new(true),
})
}
pub fn for_target(
device: ObjectIdentifier,
association: Arc<crate::audit::TargetAuditAssociation>,
) -> Arc<Self> {
Arc::new(Self {
device,
reporters: association
.reporters()
.iter()
.map(|(oid, _)| *oid)
.collect(),
association: Some(association),
active: AtomicBool::new(true),
})
}
pub fn seal(&self) {
self.active.store(false, Ordering::Release);
}
pub fn is_active(&self) -> bool {
self.active.load(Ordering::Acquire)
}
fn protects(&self, oid: &ObjectIdentifier) -> bool {
*oid == self.device || self.reporters.contains(oid)
}
}
impl ObjectDatabase {
#[doc(hidden)]
pub fn protect_audit_internal(&mut self, owner: &Arc<AuditOwnership>) -> Result<(), Error> {
self.validate_audit_installation_internal()?;
if let Some(association) = &owner.association {
association.set_subjects(self.list_objects());
}
self.audit_owner = Some(Arc::downgrade(owner));
Ok(())
}
#[doc(hidden)]
pub fn validate_audit_installation_internal(&self) -> Result<(), Error> {
if self.audit_owner.as_ref().and_then(Weak::upgrade).is_some() {
return Err(protected());
}
Ok(())
}
#[doc(hidden)]
pub fn release_audit_internal(&mut self, owner: &Arc<AuditOwnership>) {
if !owner.is_active()
&& self
.audit_owner
.as_ref()
.and_then(Weak::upgrade)
.is_some_and(|current| Arc::ptr_eq(¤t, owner))
{
self.audit_owner = None;
}
}
pub(super) fn audit_membership_changed(&self, oid: ObjectIdentifier, present: bool) {
if let Some(owner) = self.audit_owner.as_ref().and_then(Weak::upgrade) {
if let Some(association) = &owner.association {
association.membership_changed(oid, present);
}
}
}
pub(super) fn check_audit_membership(
&self,
oid: &ObjectIdentifier,
insertion: bool,
) -> Result<(), Error> {
if self
.audit_owner
.as_ref()
.and_then(Weak::upgrade)
.is_some_and(|owner| {
owner.protects(oid) || (insertion && oid.object_type() == ObjectType::DEVICE)
})
{
return Err(protected());
}
Ok(())
}
}
fn protected() -> Error {
Error::Protocol {
class: ErrorClass::OBJECT.to_raw() as u32,
code: ErrorCode::OBJECT_DELETION_NOT_PERMITTED.to_raw() as u32,
}
}