disk_core/unix_common/
validate.rs1use anyhow::{bail, Result};
7
8pub fn validate_magic(data: &[u8], offset: usize, expected: &[u8], fs_name: &str) -> Result<()> {
10 if data.len() < offset + expected.len() {
11 bail!("{fs_name}: data too short for magic check at offset {offset}");
12 }
13 if &data[offset..offset + expected.len()] != expected {
14 bail!("{fs_name}: invalid magic at offset {offset}");
15 }
16 Ok(())
17}
18
19pub fn validate_power_of_two(value: u64, name: &str) -> Result<()> {
21 if value == 0 || (value & (value - 1)) != 0 {
22 bail!("{name}: {value} is not a power of two");
23 }
24 Ok(())
25}
26
27pub fn validate_range(value: u64, min: u64, max: u64, name: &str) -> Result<()> {
29 if value < min || value > max {
30 bail!("{name}: {value} not in range [{min}, {max}]");
31 }
32 Ok(())
33}
34
35#[derive(Default)]
37pub struct ValidationResult {
38 pub warnings: Vec<String>,
39 pub errors: Vec<String>,
40}
41
42impl ValidationResult {
43 pub fn warn(&mut self, msg: impl Into<String>) {
44 self.warnings.push(msg.into());
45 }
46
47 pub fn error(&mut self, msg: impl Into<String>) {
48 self.errors.push(msg.into());
49 }
50
51 pub fn has_errors(&self) -> bool {
52 !self.errors.is_empty()
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn test_validate_magic_ok() {
62 let data = [0x53, 0xEF, 0x00, 0x00]; assert!(validate_magic(&data, 0, &[0x53, 0xEF], "ext").is_ok());
64 }
65
66 #[test]
67 fn test_validate_magic_at_offset() {
68 let data = [0x00, 0x00, 0x53, 0xEF];
69 assert!(validate_magic(&data, 2, &[0x53, 0xEF], "ext").is_ok());
70 }
71
72 #[test]
73 fn test_validate_magic_mismatch() {
74 let data = [0x00, 0x00, 0x00, 0x00];
75 let err = validate_magic(&data, 0, &[0x53, 0xEF], "ext").unwrap_err();
76 assert!(err.to_string().contains("invalid magic"));
77 }
78
79 #[test]
80 fn test_validate_magic_too_short() {
81 let data = [0x53];
82 let err = validate_magic(&data, 0, &[0x53, 0xEF], "ext").unwrap_err();
83 assert!(err.to_string().contains("too short"));
84 }
85
86 #[test]
87 fn test_validate_power_of_two_ok() {
88 assert!(validate_power_of_two(1, "block_size").is_ok());
89 assert!(validate_power_of_two(512, "block_size").is_ok());
90 assert!(validate_power_of_two(1024, "block_size").is_ok());
91 assert!(validate_power_of_two(4096, "block_size").is_ok());
92 }
93
94 #[test]
95 fn test_validate_power_of_two_zero() {
96 assert!(validate_power_of_two(0, "block_size").is_err());
97 }
98
99 #[test]
100 fn test_validate_power_of_two_non_power() {
101 let err = validate_power_of_two(3, "block_size").unwrap_err();
102 assert!(err.to_string().contains("not a power of two"));
103 }
104
105 #[test]
106 fn test_validate_range_ok() {
107 assert!(validate_range(512, 512, 4096, "block_size").is_ok());
108 assert!(validate_range(4096, 512, 4096, "block_size").is_ok());
109 assert!(validate_range(2000, 512, 4096, "block_size").is_ok());
110 }
111
112 #[test]
113 fn test_validate_range_below() {
114 let err = validate_range(256, 512, 4096, "block_size").unwrap_err();
115 assert!(err.to_string().contains("not in range"));
116 }
117
118 #[test]
119 fn test_validate_range_above() {
120 let err = validate_range(8192, 512, 4096, "block_size").unwrap_err();
121 assert!(err.to_string().contains("not in range"));
122 }
123
124 #[test]
125 fn test_validation_result() {
126 let mut vr = ValidationResult::default();
127 assert!(!vr.has_errors());
128
129 vr.warn("minor issue");
130 assert!(!vr.has_errors());
131 assert_eq!(vr.warnings.len(), 1);
132
133 vr.error("fatal problem");
134 assert!(vr.has_errors());
135 assert_eq!(vr.errors.len(), 1);
136 }
137}