use crate::engine::WfpEngine;
use crate::errors::{WfpError, WfpResult};
use windows::Win32::Foundation::ERROR_SUCCESS;
use windows::Win32::NetworkManagement::WindowsFilteringPlatform::{
FwpmTransactionAbort0, FwpmTransactionBegin0, FwpmTransactionCommit0,
};
pub struct WfpTransaction<'a> {
engine: &'a WfpEngine,
committed: bool,
}
impl<'a> WfpTransaction<'a> {
pub fn begin(engine: &'a WfpEngine) -> WfpResult<Self> {
unsafe {
let result = FwpmTransactionBegin0(engine.handle(), 0);
if result != ERROR_SUCCESS.0 {
return Err(WfpError::TransactionBeginFailed);
}
}
Ok(Self {
engine,
committed: false,
})
}
pub fn commit(mut self) -> WfpResult<()> {
unsafe {
let result = FwpmTransactionCommit0(self.engine.handle());
if result != ERROR_SUCCESS.0 {
return Err(WfpError::TransactionCommitFailed);
}
}
self.committed = true;
Ok(())
}
pub fn rollback(mut self) -> WfpResult<()> {
unsafe {
let result = FwpmTransactionAbort0(self.engine.handle());
if result != ERROR_SUCCESS.0 {
return Err(WfpError::TransactionAbortFailed);
}
}
self.committed = true; Ok(())
}
pub fn is_committed(&self) -> bool {
self.committed
}
}
impl<'a> Drop for WfpTransaction<'a> {
fn drop(&mut self) {
if !self.committed {
unsafe {
let _ = FwpmTransactionAbort0(self.engine.handle());
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[ignore] fn test_transaction_begin_commit() {
let engine = WfpEngine::new().expect("Failed to create engine");
let txn = WfpTransaction::begin(&engine).expect("Failed to begin transaction");
assert!(!txn.is_committed());
txn.commit().expect("Failed to commit transaction");
}
#[test]
#[ignore] fn test_transaction_auto_rollback() {
let engine = WfpEngine::new().expect("Failed to create engine");
{
let _txn = WfpTransaction::begin(&engine).expect("Failed to begin transaction");
}
let _txn2 = WfpTransaction::begin(&engine).expect("Failed to begin second transaction");
}
#[test]
#[ignore] fn test_transaction_explicit_rollback() {
let engine = WfpEngine::new().expect("Failed to create engine");
let txn = WfpTransaction::begin(&engine).expect("Failed to begin transaction");
txn.rollback().expect("Failed to rollback transaction");
let _txn2 = WfpTransaction::begin(&engine).expect("Failed to begin second transaction");
}
}