rustfs_filemeta/filemeta/
validation.rs1use super::*;
16
17impl FileMeta {
18 pub fn is_compatible_with_meta(&self) -> bool {
20 if self.meta_ver != XL_META_VERSION {
22 return false;
23 }
24
25 true
28 }
29
30 pub fn validate_integrity(&self) -> Result<()> {
32 if !self.is_sorted_by_mod_time() {
34 return Err(Error::other("versions not sorted by modification time"));
35 }
36
37 self.data.validate()?;
39
40 Ok(())
41 }
42
43 pub(crate) fn is_sorted_by_mod_time(&self) -> bool {
45 if self.versions.len() <= 1 {
46 return true;
47 }
48
49 for i in 1..self.versions.len() {
50 let prev_time = self.versions[i - 1].header.mod_time;
51 let curr_time = self.versions[i].header.mod_time;
52
53 match (prev_time, curr_time) {
54 (Some(prev), Some(curr)) => {
55 if prev < curr {
56 return false;
57 }
58 }
59 (None, Some(_)) => return false,
60 _ => continue,
61 }
62 }
63
64 true
65 }
66
67 pub fn get_version_stats(&self) -> VersionStats {
69 let mut stats = VersionStats {
70 total_versions: self.versions.len(),
71 ..Default::default()
72 };
73
74 for version in &self.versions {
75 match version.header.version_type {
76 VersionType::Object => stats.object_versions += 1,
77 VersionType::Delete => stats.delete_markers += 1,
78 VersionType::Invalid | VersionType::Legacy => stats.invalid_versions += 1,
79 }
80
81 if version.header.free_version() {
82 stats.free_versions += 1;
83 }
84 }
85
86 stats
87 }
88}
89
90#[derive(Debug, Default, Clone)]
91pub struct VersionStats {
92 pub total_versions: usize,
93 pub object_versions: usize,
94 pub delete_markers: usize,
95 pub invalid_versions: usize,
96 pub free_versions: usize,
97}
98
99impl FileMetaVersionHeader {
100 pub fn is_valid(&self) -> bool {
101 if !self.version_type.valid() {
103 return false;
104 }
105
106 if let Some(mod_time) = self.mod_time {
108 let now = OffsetDateTime::now_utc();
109 let future_limit = now + time::Duration::hours(24); if mod_time > future_limit {
111 return false;
112 }
113 }
114
115 if self.has_ec() && (self.ec_n == 0 || self.ec_m == 0 || self.ec_m < self.ec_n) {
117 return false;
118 }
119
120 true
121 }
122}
123
124#[derive(Debug, Default, Clone)]
126pub struct DetailedVersionStats {
127 pub total_versions: usize,
128 pub object_versions: usize,
129 pub delete_markers: usize,
130 pub invalid_versions: usize,
131 pub legacy_versions: usize,
132 pub free_versions: usize,
133 pub versions_with_data_dir: usize,
134 pub versions_with_inline_data: usize,
135 pub total_size: i64,
136 pub latest_mod_time: Option<OffsetDateTime>,
137}
138
139impl FileMeta {
140 pub fn get_detailed_version_stats(&self) -> DetailedVersionStats {
142 let mut stats = DetailedVersionStats {
143 total_versions: self.versions.len(),
144 ..Default::default()
145 };
146
147 for version in &self.versions {
148 match version.header.version_type {
149 VersionType::Object => {
150 stats.object_versions += 1;
151 if let Ok(ver) = FileMetaVersion::try_from(version.meta.as_slice())
152 && let Some(obj) = &ver.object
153 {
154 stats.total_size += obj.size;
155 if obj.uses_data_dir() {
156 stats.versions_with_data_dir += 1;
157 }
158 if obj.inlinedata() {
159 stats.versions_with_inline_data += 1;
160 }
161 }
162 }
163 VersionType::Delete => stats.delete_markers += 1,
164 VersionType::Legacy => stats.legacy_versions += 1,
165 VersionType::Invalid => stats.invalid_versions += 1,
166 }
167
168 if version.header.free_version() {
169 stats.free_versions += 1;
170 }
171
172 if stats.latest_mod_time.is_none()
173 || (version.header.mod_time.is_some() && version.header.mod_time > stats.latest_mod_time)
174 {
175 stats.latest_mod_time = version.header.mod_time;
176 }
177 }
178
179 stats
180 }
181}