rebecca-windows 0.3.0

Windows-specific adapters for Rebecca discovery and host capabilities.
Documentation
use std::path::Path;

use rebecca_core::RebeccaError;
use rebecca_core::scan_cache::{
    ScanCacheRecord, ScanCacheUsnChange, ScanCacheUsnInvalidationReason, ScanCacheUsnJournalState,
    ScanCacheUsnValidation, ScanCacheUsnValidator,
};

pub const USN_CACHE_VALIDATION_LABEL: &str = "windows-usn-cache-validation";

pub fn live_usn_cache_validation_unavailable(path: &Path) -> RebeccaError {
    RebeccaError::PlatformUnavailable(format!(
        "{USN_CACHE_VALIDATION_LABEL} is not enabled for {}; falling back to normal scan-cache fingerprint and identity policy",
        path.display()
    ))
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SnapshotUsnCacheValidator {
    journal_state: Option<ScanCacheUsnJournalState>,
    changes: Vec<ScanCacheUsnChange>,
    range_readable: bool,
}

impl SnapshotUsnCacheValidator {
    pub fn unsupported() -> Self {
        Self {
            journal_state: None,
            changes: Vec::new(),
            range_readable: false,
        }
    }

    pub fn readable(
        journal_state: ScanCacheUsnJournalState,
        changes: Vec<ScanCacheUsnChange>,
    ) -> Self {
        Self {
            journal_state: Some(journal_state),
            changes,
            range_readable: true,
        }
    }

    pub fn unreadable_range(journal_state: ScanCacheUsnJournalState) -> Self {
        Self {
            journal_state: Some(journal_state),
            changes: Vec::new(),
            range_readable: false,
        }
    }
}

impl ScanCacheUsnValidator for SnapshotUsnCacheValidator {
    fn validate_record(&self, record: &ScanCacheRecord) -> ScanCacheUsnValidation {
        if record.identity.usn_checkpoint.is_none() {
            return ScanCacheUsnValidation::Unsupported;
        }

        let Some(journal_state) = &self.journal_state else {
            return ScanCacheUsnValidation::Unsupported;
        };

        if !self.range_readable {
            return ScanCacheUsnValidation::Invalidated(
                ScanCacheUsnInvalidationReason::RangeUnavailable,
            );
        }

        record.validate_usn_journal(journal_state, &self.changes)
    }
}