Mercurial > hg
comparison rust/hg-core/src/dirstate_tree/on_disk.rs @ 49373:f8ec7b16c98f stable
rust: add message to `DirstateV2ParseError` to give some context
This is useful when debugging.
author | Raphaël Gomès <rgomes@octobus.net> |
---|---|
date | Wed, 18 May 2022 09:50:39 +0100 |
parents | 288de6f5d724 |
children | c7fb9b74e753 f2e13d8d30e0 |
comparison
equal
deleted
inserted
replaced
49372:270f8e89ff32 | 49373:f8ec7b16c98f |
---|---|
173 | 173 |
174 /// Unexpected file format found in `.hg/dirstate` with the "v2" format. | 174 /// Unexpected file format found in `.hg/dirstate` with the "v2" format. |
175 /// | 175 /// |
176 /// This should only happen if Mercurial is buggy or a repository is corrupted. | 176 /// This should only happen if Mercurial is buggy or a repository is corrupted. |
177 #[derive(Debug)] | 177 #[derive(Debug)] |
178 pub struct DirstateV2ParseError; | 178 pub struct DirstateV2ParseError { |
179 message: String, | |
180 } | |
181 | |
182 impl DirstateV2ParseError { | |
183 pub fn new<S: Into<String>>(message: S) -> Self { | |
184 Self { | |
185 message: message.into(), | |
186 } | |
187 } | |
188 } | |
179 | 189 |
180 impl From<DirstateV2ParseError> for HgError { | 190 impl From<DirstateV2ParseError> for HgError { |
181 fn from(_: DirstateV2ParseError) -> Self { | 191 fn from(e: DirstateV2ParseError) -> Self { |
182 HgError::corrupted("dirstate-v2 parse error") | 192 HgError::corrupted(format!("dirstate-v2 parse error: {}", e.message)) |
183 } | 193 } |
184 } | 194 } |
185 | 195 |
186 impl From<DirstateV2ParseError> for crate::DirstateError { | 196 impl From<DirstateV2ParseError> for crate::DirstateError { |
187 fn from(error: DirstateV2ParseError) -> Self { | 197 fn from(error: DirstateV2ParseError) -> Self { |
260 } | 270 } |
261 | 271 |
262 pub fn read_docket( | 272 pub fn read_docket( |
263 on_disk: &[u8], | 273 on_disk: &[u8], |
264 ) -> Result<Docket<'_>, DirstateV2ParseError> { | 274 ) -> Result<Docket<'_>, DirstateV2ParseError> { |
265 let (header, uuid) = | 275 let (header, uuid) = DocketHeader::from_bytes(on_disk).map_err(|e| { |
266 DocketHeader::from_bytes(on_disk).map_err(|_| DirstateV2ParseError)?; | 276 DirstateV2ParseError::new(format!("when reading docket, {}", e)) |
277 })?; | |
267 let uuid_size = header.uuid_size as usize; | 278 let uuid_size = header.uuid_size as usize; |
268 if header.marker == *V2_FORMAT_MARKER && uuid.len() == uuid_size { | 279 if header.marker == *V2_FORMAT_MARKER && uuid.len() == uuid_size { |
269 Ok(Docket { header, uuid }) | 280 Ok(Docket { header, uuid }) |
270 } else { | 281 } else { |
271 Err(DirstateV2ParseError) | 282 Err(DirstateV2ParseError::new( |
283 "invalid format marker or uuid size", | |
284 )) | |
272 } | 285 } |
273 } | 286 } |
274 | 287 |
275 pub(super) fn read<'on_disk>( | 288 pub(super) fn read<'on_disk>( |
276 on_disk: &'on_disk [u8], | 289 on_disk: &'on_disk [u8], |
279 if on_disk.is_empty() { | 292 if on_disk.is_empty() { |
280 let mut map = DirstateMap::empty(on_disk); | 293 let mut map = DirstateMap::empty(on_disk); |
281 map.dirstate_version = DirstateVersion::V2; | 294 map.dirstate_version = DirstateVersion::V2; |
282 return Ok(map); | 295 return Ok(map); |
283 } | 296 } |
284 let (meta, _) = TreeMetadata::from_bytes(metadata) | 297 let (meta, _) = TreeMetadata::from_bytes(metadata).map_err(|e| { |
285 .map_err(|_| DirstateV2ParseError)?; | 298 DirstateV2ParseError::new(format!("when parsing tree metadata, {}", e)) |
299 })?; | |
286 let dirstate_map = DirstateMap { | 300 let dirstate_map = DirstateMap { |
287 on_disk, | 301 on_disk, |
288 root: dirstate_map::ChildNodes::OnDisk(read_nodes( | 302 root: dirstate_map::ChildNodes::OnDisk( |
289 on_disk, | 303 read_nodes(on_disk, meta.root_nodes).map_err(|mut e| { |
290 meta.root_nodes, | 304 e.message = format!("{}, when reading root notes", e.message); |
291 )?), | 305 e |
306 })?, | |
307 ), | |
292 nodes_with_entry_count: meta.nodes_with_entry_count.get(), | 308 nodes_with_entry_count: meta.nodes_with_entry_count.get(), |
293 nodes_with_copy_source_count: meta.nodes_with_copy_source_count.get(), | 309 nodes_with_copy_source_count: meta.nodes_with_copy_source_count.get(), |
294 ignore_patterns_hash: meta.ignore_patterns_hash, | 310 ignore_patterns_hash: meta.ignore_patterns_hash, |
295 unreachable_bytes: meta.unreachable_bytes.get(), | 311 unreachable_bytes: meta.unreachable_bytes.get(), |
296 old_data_size: on_disk.len(), | 312 old_data_size: on_disk.len(), |
315 let start = usize::try_from(start) | 331 let start = usize::try_from(start) |
316 // u32 -> usize, could only panic on a 16-bit CPU | 332 // u32 -> usize, could only panic on a 16-bit CPU |
317 .expect("dirstate-v2 base_name_start out of bounds"); | 333 .expect("dirstate-v2 base_name_start out of bounds"); |
318 Ok(start) | 334 Ok(start) |
319 } else { | 335 } else { |
320 Err(DirstateV2ParseError) | 336 Err(DirstateV2ParseError::new("not enough bytes for base name")) |
321 } | 337 } |
322 } | 338 } |
323 | 339 |
324 pub(super) fn base_name<'on_disk>( | 340 pub(super) fn base_name<'on_disk>( |
325 &self, | 341 &self, |
569 { | 585 { |
570 // Either `usize::MAX` would result in "out of bounds" error since a single | 586 // Either `usize::MAX` would result in "out of bounds" error since a single |
571 // `&[u8]` cannot occupy the entire addess space. | 587 // `&[u8]` cannot occupy the entire addess space. |
572 let start = start.get().try_into().unwrap_or(std::usize::MAX); | 588 let start = start.get().try_into().unwrap_or(std::usize::MAX); |
573 let len = len.try_into().unwrap_or(std::usize::MAX); | 589 let len = len.try_into().unwrap_or(std::usize::MAX); |
574 on_disk | 590 let bytes = match on_disk.get(start..) { |
575 .get(start..) | 591 Some(bytes) => bytes, |
576 .and_then(|bytes| T::slice_from_bytes(bytes, len).ok()) | 592 None => { |
593 return Err(DirstateV2ParseError::new( | |
594 "not enough bytes from disk", | |
595 )) | |
596 } | |
597 }; | |
598 T::slice_from_bytes(bytes, len) | |
599 .map_err(|e| { | |
600 DirstateV2ParseError::new(format!("when reading a slice, {}", e)) | |
601 }) | |
577 .map(|(slice, _rest)| slice) | 602 .map(|(slice, _rest)| slice) |
578 .ok_or_else(|| DirstateV2ParseError) | |
579 } | 603 } |
580 | 604 |
581 pub(crate) fn for_each_tracked_path<'on_disk>( | 605 pub(crate) fn for_each_tracked_path<'on_disk>( |
582 on_disk: &'on_disk [u8], | 606 on_disk: &'on_disk [u8], |
583 metadata: &[u8], | 607 metadata: &[u8], |
584 mut f: impl FnMut(&'on_disk HgPath), | 608 mut f: impl FnMut(&'on_disk HgPath), |
585 ) -> Result<(), DirstateV2ParseError> { | 609 ) -> Result<(), DirstateV2ParseError> { |
586 let (meta, _) = TreeMetadata::from_bytes(metadata) | 610 let (meta, _) = TreeMetadata::from_bytes(metadata).map_err(|e| { |
587 .map_err(|_| DirstateV2ParseError)?; | 611 DirstateV2ParseError::new(format!("when parsing tree metadata, {}", e)) |
612 })?; | |
588 fn recur<'on_disk>( | 613 fn recur<'on_disk>( |
589 on_disk: &'on_disk [u8], | 614 on_disk: &'on_disk [u8], |
590 nodes: ChildNodes, | 615 nodes: ChildNodes, |
591 f: &mut impl FnMut(&'on_disk HgPath), | 616 f: &mut impl FnMut(&'on_disk HgPath), |
592 ) -> Result<(), DirstateV2ParseError> { | 617 ) -> Result<(), DirstateV2ParseError> { |