rust/hg-core/src/dirstate_tree/on_disk.rs
branchstable
changeset 49373 f8ec7b16c98f
parent 49366 288de6f5d724
child 49630 c7fb9b74e753
child 50179 f2e13d8d30e0
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> {