Skip to main content

evaluate_rules

Function evaluate_rules 

Source
pub fn evaluate_rules(
    rules: &[MagicRule],
    buffer: &[u8],
    context: &mut EvaluationContext,
) -> Result<Vec<RuleMatch>, LibmagicError>
Expand description

Evaluate a list of magic rules against a file buffer with hierarchical processing

This function implements the core hierarchical rule evaluation algorithm with graceful error handling:

  1. Evaluates each top-level rule in sequence
  2. If a parent rule matches, evaluates its child rules for refinement
  3. Collects all matches or stops at first match based on configuration
  4. Maintains evaluation context for recursion limits and state
  5. Implements graceful degradation by skipping problematic rules and continuing evaluation

The hierarchical evaluation follows these principles:

  • Parent rules must match before children are evaluated
  • Child rules provide refinement and additional detail
  • Evaluation can stop at first match or continue for all matches
  • Recursion depth is limited to prevent infinite loops
  • Problematic rules are skipped to allow evaluation to continue

§Arguments

  • rules - The list of magic rules to evaluate
  • buffer - The file buffer to evaluate against
  • context - Mutable evaluation context for state management. Callers reusing a context across multiple buffers must call EvaluationContext::reset between calls – the GNU file previous-match anchor and the recursion-depth counter both advance during evaluation and would otherwise leak across buffers. The same applies when this function returns Err mid-evaluation (e.g., LibmagicError::Timeout or RecursionLimitExceeded): both the anchor and (potentially) the recursion depth are left in a partially-advanced state, and a retry on the same context without reset() will resolve relative offsets against the stale anchor and apply the wrong recursion budget. evaluate_rules_with_config always builds a fresh context and is the safer choice when context reuse isn’t required.

§Returns

Returns Ok(Vec<RuleMatch>) containing all matches found. Errors in individual rules are skipped to allow evaluation to continue. Only returns Err(LibmagicError) for critical failures like timeout or recursion limit exceeded.

§Examples

use libmagic_rs::evaluator::{evaluate_rules, EvaluationContext, RuleMatch};
use libmagic_rs::parser::ast::{MagicRule, OffsetSpec, TypeKind, Operator, Value};
use libmagic_rs::EvaluationConfig;

// Create a hierarchical rule set for ELF files
let parent_rule = MagicRule {
    offset: OffsetSpec::Absolute(0),
    typ: TypeKind::Byte { signed: true },
    op: Operator::Equal,
    value: Value::Uint(0x7f),
    message: "ELF".to_string(),
    children: vec![
        MagicRule {
            offset: OffsetSpec::Absolute(4),
            typ: TypeKind::Byte { signed: true },
            op: Operator::Equal,
            value: Value::Uint(2),
            message: "64-bit".to_string(),
            children: vec![],
            level: 1,
            strength_modifier: None,
        value_transform: None,
        }
    ],
    level: 0,
    strength_modifier: None,
value_transform: None,
};

let rules = vec![parent_rule];
let buffer = &[0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01]; // ELF64 header
let config = EvaluationConfig::default();
let mut context = EvaluationContext::new(config);

let matches = evaluate_rules(&rules, buffer, &mut context).unwrap();
assert_eq!(matches.len(), 2); // Parent and child should both match

§Errors

  • LibmagicError::Timeout - If evaluation exceeds configured timeout
  • LibmagicError::EvaluationError - Only for critical failures like recursion limit exceeded

Individual rule evaluation errors are handled gracefully and do not stop the overall evaluation.