Skip to main content

winreg_core/
error.rs

1//! Error types for registry hive parsing.
2
3use miette::Diagnostic;
4use thiserror::Error;
5use winreg_format::cells::CellOffset;
6
7/// All errors from winreg-core.
8#[derive(Debug, Error, Diagnostic)]
9pub enum HiveError {
10    #[error("Invalid regf signature — not a registry hive file")]
11    #[diagnostic(code(winreg::invalid_signature))]
12    InvalidSignature,
13
14    #[error("Base block checksum mismatch: expected {expected:#010X}, computed {computed:#010X}")]
15    #[diagnostic(code(winreg::checksum_mismatch))]
16    ChecksumMismatch { expected: u32, computed: u32 },
17
18    #[error("Unsupported REGF version: {major}.{minor}")]
19    #[diagnostic(code(winreg::unsupported_version))]
20    UnsupportedVersion { major: u32, minor: u32 },
21
22    #[error("Cell at offset {offset} extends beyond hbin boundary (cell size: {cell_size}, hbin ends at: {hbin_end})")]
23    #[diagnostic(code(winreg::cell_overflow))]
24    CellOverflow {
25        offset: CellOffset,
26        cell_size: u32,
27        hbin_end: u64,
28    },
29
30    #[error("Invalid cell signature at offset {offset}: expected {expected}, got [{byte0:#04X}, {byte1:#04X}]")]
31    #[diagnostic(code(winreg::invalid_cell_signature))]
32    InvalidCellSignature {
33        offset: CellOffset,
34        expected: &'static str,
35        byte0: u8,
36        byte1: u8,
37    },
38
39    #[error("Cell at offset {offset} is unallocated (free cell)")]
40    #[diagnostic(code(winreg::unallocated_cell))]
41    UnallocatedCell { offset: CellOffset },
42
43    #[error("Null cell offset encountered where a valid offset was expected")]
44    #[diagnostic(code(winreg::null_offset))]
45    NullOffset,
46
47    #[error("Hive bins data is truncated: expected {expected} bytes, got {actual}")]
48    #[diagnostic(code(winreg::truncated_hive))]
49    TruncatedHive { expected: u64, actual: u64 },
50
51    #[error("Invalid hbin at file offset {file_offset}: bad signature")]
52    #[diagnostic(code(winreg::invalid_hbin))]
53    InvalidHbin { file_offset: u64 },
54
55    #[error("Key not found: {path}")]
56    #[diagnostic(code(winreg::key_not_found))]
57    KeyNotFound { path: String },
58
59    #[error("Value not found: {name} under key {key_path}")]
60    #[diagnostic(code(winreg::value_not_found))]
61    ValueNotFound { name: String, key_path: String },
62
63    #[error("I/O error: {0}")]
64    #[diagnostic(code(winreg::io))]
65    Io(#[from] std::io::Error),
66}
67
68/// Result type alias for winreg-core.
69pub type Result<T> = std::result::Result<T, HiveError>;
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn error_display_messages() {
77        let err = HiveError::ChecksumMismatch {
78            expected: 0x1234_5678,
79            computed: 0xDEAD_BEEF,
80        };
81        let msg = format!("{err}");
82        assert!(msg.contains("0x12345678"));
83        assert!(msg.contains("0xDEADBEEF"));
84    }
85
86    #[test]
87    fn error_is_send_sync() {
88        fn assert_send_sync<T: Send + Sync>() {}
89        assert_send_sync::<HiveError>();
90    }
91
92    #[test]
93    fn io_error_converts() {
94        let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file missing");
95        let hive_err: HiveError = io_err.into();
96        assert!(matches!(hive_err, HiveError::Io(_)));
97    }
98}