rust/hg-core/src/revlog/revlog.rs
changeset 48458 96ea4db4741b
parent 48457 1fb3615dfce2
child 48540 20d0d896183e
--- 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<RevlogEntry, RevlogError> {
+        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<Revision>,
+    base_rev_or_base_of_delta_chain: Option<Revision>,
 }
 
 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()
     }
 }