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> {