diff -r 1fb3615dfce2 -r 96ea4db4741b rust/hg-core/src/revlog/revlog.rs --- a/rust/hg-core/src/revlog/revlog.rs Tue Dec 07 18:12:13 2021 +0000 +++ b/rust/hg-core/src/revlog/revlog.rs Tue Dec 07 18:57:43 2021 +0000 @@ -191,11 +191,20 @@ // Todo return -> Cow let mut entry = self.get_entry(rev)?; let mut delta_chain = vec![]; - while let Some(base_rev) = entry.base_rev { + + // The meaning of `base_rev_or_base_of_delta_chain` depends on + // generaldelta. See the doc on `ENTRY_DELTA_BASE` in + // `mercurial/revlogutils/constants.py` and the code in + // [_chaininfo] and in [index_deltachain]. + let uses_generaldelta = self.index.uses_generaldelta(); + while let Some(base_rev) = entry.base_rev_or_base_of_delta_chain { + let base_rev = if uses_generaldelta { + base_rev + } else { + entry.rev - 1 + }; delta_chain.push(entry); - entry = self - .get_entry(base_rev) - .map_err(|_| RevlogError::corrupted())?; + entry = self.get_entry_internal(base_rev)?; } // TODO do not look twice in the index @@ -291,14 +300,26 @@ bytes: data, compressed_len: index_entry.compressed_len(), uncompressed_len: index_entry.uncompressed_len(), - base_rev: if index_entry.base_revision() == rev { + base_rev_or_base_of_delta_chain: if index_entry + .base_revision_or_base_of_delta_chain() + == rev + { None } else { - Some(index_entry.base_revision()) + Some(index_entry.base_revision_or_base_of_delta_chain()) }, }; Ok(entry) } + + /// when resolving internal references within revlog, any errors + /// should be reported as corruption, instead of e.g. "invalid revision" + fn get_entry_internal( + &self, + rev: Revision, + ) -> Result { + return self.get_entry(rev).map_err(|_| RevlogError::corrupted()); + } } /// The revlog entry's bytes and the necessary informations to extract @@ -309,7 +330,7 @@ bytes: &'a [u8], compressed_len: usize, uncompressed_len: usize, - base_rev: Option, + base_rev_or_base_of_delta_chain: Option, } impl<'a> RevlogEntry<'a> { @@ -375,7 +396,7 @@ /// Tell if the entry is a snapshot or a delta /// (influences on decompression). fn is_delta(&self) -> bool { - self.base_rev.is_some() + self.base_rev_or_base_of_delta_chain.is_some() } }