##// END OF EJS Templates
rhg: fix a crash on non-generaldelta revlogs...
Arseniy Alekseyev -
r49289:96ea4db4 default
parent child Browse files
Show More
@@ -84,6 +84,7 b' pub struct Index {'
84 /// Offsets of starts of index blocks.
84 /// Offsets of starts of index blocks.
85 /// Only needed when the index is interleaved with data.
85 /// Only needed when the index is interleaved with data.
86 offsets: Option<Vec<usize>>,
86 offsets: Option<Vec<usize>>,
87 uses_generaldelta: bool,
87 }
88 }
88
89
89 impl Index {
90 impl Index {
@@ -100,6 +101,11 b' impl Index {'
100 return Err(HgError::corrupted("unsupported revlog version"));
101 return Err(HgError::corrupted("unsupported revlog version"));
101 }
102 }
102
103
104 // This is only correct because we know version is REVLOGV1.
105 // In v2 we always use generaldelta, while in v0 we never use
106 // generaldelta. Similar for [is_inline] (it's only used in v1).
107 let uses_generaldelta = header.format_flags().uses_generaldelta();
108
103 if header.format_flags().is_inline() {
109 if header.format_flags().is_inline() {
104 let mut offset: usize = 0;
110 let mut offset: usize = 0;
105 let mut offsets = Vec::new();
111 let mut offsets = Vec::new();
@@ -119,6 +125,7 b' impl Index {'
119 Ok(Self {
125 Ok(Self {
120 bytes,
126 bytes,
121 offsets: Some(offsets),
127 offsets: Some(offsets),
128 uses_generaldelta,
122 })
129 })
123 } else {
130 } else {
124 Err(HgError::corrupted("unexpected inline revlog length")
131 Err(HgError::corrupted("unexpected inline revlog length")
@@ -128,10 +135,15 b' impl Index {'
128 Ok(Self {
135 Ok(Self {
129 bytes,
136 bytes,
130 offsets: None,
137 offsets: None,
138 uses_generaldelta,
131 })
139 })
132 }
140 }
133 }
141 }
134
142
143 pub fn uses_generaldelta(&self) -> bool {
144 self.uses_generaldelta
145 }
146
135 /// Value of the inline flag.
147 /// Value of the inline flag.
136 pub fn is_inline(&self) -> bool {
148 pub fn is_inline(&self) -> bool {
137 self.offsets.is_some()
149 self.offsets.is_some()
@@ -259,7 +271,7 b" impl<'a> IndexEntry<'a> {"
259 }
271 }
260
272
261 /// Return the revision upon which the data has been derived.
273 /// Return the revision upon which the data has been derived.
262 pub fn base_revision(&self) -> Revision {
274 pub fn base_revision_or_base_of_delta_chain(&self) -> Revision {
263 // TODO Maybe return an Option when base_revision == rev?
275 // TODO Maybe return an Option when base_revision == rev?
264 // Requires to add rev to IndexEntry
276 // Requires to add rev to IndexEntry
265
277
@@ -297,7 +309,7 b' mod tests {'
297 offset: usize,
309 offset: usize,
298 compressed_len: usize,
310 compressed_len: usize,
299 uncompressed_len: usize,
311 uncompressed_len: usize,
300 base_revision: Revision,
312 base_revision_or_base_of_delta_chain: Revision,
301 }
313 }
302
314
303 #[cfg(test)]
315 #[cfg(test)]
@@ -311,7 +323,7 b' mod tests {'
311 offset: 0,
323 offset: 0,
312 compressed_len: 0,
324 compressed_len: 0,
313 uncompressed_len: 0,
325 uncompressed_len: 0,
314 base_revision: 0,
326 base_revision_or_base_of_delta_chain: 0,
315 }
327 }
316 }
328 }
317
329
@@ -350,8 +362,11 b' mod tests {'
350 self
362 self
351 }
363 }
352
364
353 pub fn with_base_revision(&mut self, value: Revision) -> &mut Self {
365 pub fn with_base_revision_or_base_of_delta_chain(
354 self.base_revision = value;
366 &mut self,
367 value: Revision,
368 ) -> &mut Self {
369 self.base_revision_or_base_of_delta_chain = value;
355 self
370 self
356 }
371 }
357
372
@@ -374,7 +389,9 b' mod tests {'
374 bytes.extend(&[0u8; 2]); // Revision flags.
389 bytes.extend(&[0u8; 2]); // Revision flags.
375 bytes.extend(&(self.compressed_len as u32).to_be_bytes());
390 bytes.extend(&(self.compressed_len as u32).to_be_bytes());
376 bytes.extend(&(self.uncompressed_len as u32).to_be_bytes());
391 bytes.extend(&(self.uncompressed_len as u32).to_be_bytes());
377 bytes.extend(&self.base_revision.to_be_bytes());
392 bytes.extend(
393 &self.base_revision_or_base_of_delta_chain.to_be_bytes(),
394 );
378 bytes
395 bytes
379 }
396 }
380 }
397 }
@@ -480,14 +497,16 b' mod tests {'
480 }
497 }
481
498
482 #[test]
499 #[test]
483 fn test_base_revision() {
500 fn test_base_revision_or_base_of_delta_chain() {
484 let bytes = IndexEntryBuilder::new().with_base_revision(1).build();
501 let bytes = IndexEntryBuilder::new()
502 .with_base_revision_or_base_of_delta_chain(1)
503 .build();
485 let entry = IndexEntry {
504 let entry = IndexEntry {
486 bytes: &bytes,
505 bytes: &bytes,
487 offset_override: None,
506 offset_override: None,
488 };
507 };
489
508
490 assert_eq!(entry.base_revision(), 1)
509 assert_eq!(entry.base_revision_or_base_of_delta_chain(), 1)
491 }
510 }
492
511
493 #[test]
512 #[test]
@@ -191,11 +191,20 b' impl Revlog {'
191 // Todo return -> Cow
191 // Todo return -> Cow
192 let mut entry = self.get_entry(rev)?;
192 let mut entry = self.get_entry(rev)?;
193 let mut delta_chain = vec![];
193 let mut delta_chain = vec![];
194 while let Some(base_rev) = entry.base_rev {
194
195 // The meaning of `base_rev_or_base_of_delta_chain` depends on
196 // generaldelta. See the doc on `ENTRY_DELTA_BASE` in
197 // `mercurial/revlogutils/constants.py` and the code in
198 // [_chaininfo] and in [index_deltachain].
199 let uses_generaldelta = self.index.uses_generaldelta();
200 while let Some(base_rev) = entry.base_rev_or_base_of_delta_chain {
201 let base_rev = if uses_generaldelta {
202 base_rev
203 } else {
204 entry.rev - 1
205 };
195 delta_chain.push(entry);
206 delta_chain.push(entry);
196 entry = self
207 entry = self.get_entry_internal(base_rev)?;
197 .get_entry(base_rev)
198 .map_err(|_| RevlogError::corrupted())?;
199 }
208 }
200
209
201 // TODO do not look twice in the index
210 // TODO do not look twice in the index
@@ -291,14 +300,26 b' impl Revlog {'
291 bytes: data,
300 bytes: data,
292 compressed_len: index_entry.compressed_len(),
301 compressed_len: index_entry.compressed_len(),
293 uncompressed_len: index_entry.uncompressed_len(),
302 uncompressed_len: index_entry.uncompressed_len(),
294 base_rev: if index_entry.base_revision() == rev {
303 base_rev_or_base_of_delta_chain: if index_entry
304 .base_revision_or_base_of_delta_chain()
305 == rev
306 {
295 None
307 None
296 } else {
308 } else {
297 Some(index_entry.base_revision())
309 Some(index_entry.base_revision_or_base_of_delta_chain())
298 },
310 },
299 };
311 };
300 Ok(entry)
312 Ok(entry)
301 }
313 }
314
315 /// when resolving internal references within revlog, any errors
316 /// should be reported as corruption, instead of e.g. "invalid revision"
317 fn get_entry_internal(
318 &self,
319 rev: Revision,
320 ) -> Result<RevlogEntry, RevlogError> {
321 return self.get_entry(rev).map_err(|_| RevlogError::corrupted());
322 }
302 }
323 }
303
324
304 /// The revlog entry's bytes and the necessary informations to extract
325 /// The revlog entry's bytes and the necessary informations to extract
@@ -309,7 +330,7 b" pub struct RevlogEntry<'a> {"
309 bytes: &'a [u8],
330 bytes: &'a [u8],
310 compressed_len: usize,
331 compressed_len: usize,
311 uncompressed_len: usize,
332 uncompressed_len: usize,
312 base_rev: Option<Revision>,
333 base_rev_or_base_of_delta_chain: Option<Revision>,
313 }
334 }
314
335
315 impl<'a> RevlogEntry<'a> {
336 impl<'a> RevlogEntry<'a> {
@@ -375,7 +396,7 b" impl<'a> RevlogEntry<'a> {"
375 /// Tell if the entry is a snapshot or a delta
396 /// Tell if the entry is a snapshot or a delta
376 /// (influences on decompression).
397 /// (influences on decompression).
377 fn is_delta(&self) -> bool {
398 fn is_delta(&self) -> bool {
378 self.base_rev.is_some()
399 self.base_rev_or_base_of_delta_chain.is_some()
379 }
400 }
380 }
401 }
381
402
@@ -1,4 +1,3 b''
1
2 $ NO_FALLBACK="env RHG_ON_UNSUPPORTED=abort"
1 $ NO_FALLBACK="env RHG_ON_UNSUPPORTED=abort"
3
2
4 $ cat << EOF >> $HGRCPATH
3 $ cat << EOF >> $HGRCPATH
@@ -21,9 +20,27 b''
21 1 0 prev
20 1 0 prev
22 2 1 prev
21 2 1 prev
23
22
24 rhg breaks on non-generaldelta revlogs:
23 rhg works on non-generaldelta revlogs:
25
24
26 $ $NO_FALLBACK hg cat f -r . | f --sha256 --size
25 $ $NO_FALLBACK hg cat f -r .
27 abort: corrupted revlog (rhg !)
26 1
28 size=0, sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 (rhg !)
27 2
29 size=58, sha256=0cf0386dd4813cc3b957ea790146627dfc0ec42ad3fcf47221b9842e4d5764c1 (no-rhg !)
28 3
29 4
30 5
31 6
32 7
33 8
34 9
35 10
36 11
37 12
38 13
39 14
40 15
41 16
42 17
43 18
44 19
45 20
46 footer
General Comments 0
You need to be logged in to leave comments. Login now