182 /// |
182 /// |
183 /// All entries required to build the final data out of deltas will be |
183 /// All entries required to build the final data out of deltas will be |
184 /// retrieved as needed, and the deltas will be applied to the inital |
184 /// retrieved as needed, and the deltas will be applied to the inital |
185 /// snapshot to rebuild the final data. |
185 /// snapshot to rebuild the final data. |
186 #[timed] |
186 #[timed] |
187 pub fn get_rev_data(&self, rev: Revision) -> Result<Vec<u8>, RevlogError> { |
187 pub fn get_rev_data( |
|
188 &self, |
|
189 rev: Revision, |
|
190 ) -> Result<Cow<[u8]>, RevlogError> { |
188 if rev == NULL_REVISION { |
191 if rev == NULL_REVISION { |
189 return Ok(vec![]); |
192 return Ok(Cow::Borrowed(&[])); |
190 }; |
193 }; |
191 // Todo return -> Cow |
194 self.get_entry(rev)?.data() |
192 let mut entry = self.get_entry(rev)?; |
|
193 let mut delta_chain = vec![]; |
|
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 }; |
|
206 delta_chain.push(entry); |
|
207 entry = self.get_entry_internal(base_rev)?; |
|
208 } |
|
209 |
|
210 // TODO do not look twice in the index |
|
211 let index_entry = self |
|
212 .index |
|
213 .get_entry(rev) |
|
214 .ok_or(RevlogError::InvalidRevision)?; |
|
215 |
|
216 let data: Vec<u8> = if delta_chain.is_empty() { |
|
217 entry.data_chunk()?.into() |
|
218 } else { |
|
219 Revlog::build_data_from_deltas(entry, &delta_chain)? |
|
220 }; |
|
221 |
|
222 if self.check_hash( |
|
223 index_entry.p1(), |
|
224 index_entry.p2(), |
|
225 index_entry.hash().as_bytes(), |
|
226 &data, |
|
227 ) { |
|
228 Ok(data) |
|
229 } else { |
|
230 Err(RevlogError::corrupted()) |
|
231 } |
|
232 } |
195 } |
233 |
196 |
234 /// Check the hash of some given data against the recorded hash. |
197 /// Check the hash of some given data against the recorded hash. |
235 pub fn check_hash( |
198 pub fn check_hash( |
236 &self, |
199 &self, |
294 self.index.data(start, end) |
257 self.index.data(start, end) |
295 } else { |
258 } else { |
296 &self.data()[start..end] |
259 &self.data()[start..end] |
297 }; |
260 }; |
298 let entry = RevlogEntry { |
261 let entry = RevlogEntry { |
|
262 revlog: self, |
299 rev, |
263 rev, |
300 bytes: data, |
264 bytes: data, |
301 compressed_len: index_entry.compressed_len(), |
265 compressed_len: index_entry.compressed_len(), |
302 uncompressed_len: index_entry.uncompressed_len(), |
266 uncompressed_len: index_entry.uncompressed_len(), |
303 base_rev_or_base_of_delta_chain: if index_entry |
267 base_rev_or_base_of_delta_chain: if index_entry |
322 } |
286 } |
323 } |
287 } |
324 |
288 |
325 /// The revlog entry's bytes and the necessary informations to extract |
289 /// The revlog entry's bytes and the necessary informations to extract |
326 /// the entry's data. |
290 /// the entry's data. |
327 #[derive(Debug)] |
291 #[derive(Clone)] |
328 pub struct RevlogEntry<'a> { |
292 pub struct RevlogEntry<'a> { |
|
293 revlog: &'a Revlog, |
329 rev: Revision, |
294 rev: Revision, |
330 bytes: &'a [u8], |
295 bytes: &'a [u8], |
331 compressed_len: usize, |
296 compressed_len: usize, |
332 uncompressed_len: usize, |
297 uncompressed_len: usize, |
333 base_rev_or_base_of_delta_chain: Option<Revision>, |
298 base_rev_or_base_of_delta_chain: Option<Revision>, |
336 impl<'a> RevlogEntry<'a> { |
301 impl<'a> RevlogEntry<'a> { |
337 pub fn revision(&self) -> Revision { |
302 pub fn revision(&self) -> Revision { |
338 self.rev |
303 self.rev |
339 } |
304 } |
340 |
305 |
|
306 /// The data for this entry, after resolving deltas if any. |
|
307 pub fn data(&self) -> Result<Cow<'a, [u8]>, RevlogError> { |
|
308 let mut entry = self.clone(); |
|
309 let mut delta_chain = vec![]; |
|
310 |
|
311 // The meaning of `base_rev_or_base_of_delta_chain` depends on |
|
312 // generaldelta. See the doc on `ENTRY_DELTA_BASE` in |
|
313 // `mercurial/revlogutils/constants.py` and the code in |
|
314 // [_chaininfo] and in [index_deltachain]. |
|
315 let uses_generaldelta = self.revlog.index.uses_generaldelta(); |
|
316 while let Some(base_rev) = entry.base_rev_or_base_of_delta_chain { |
|
317 let base_rev = if uses_generaldelta { |
|
318 base_rev |
|
319 } else { |
|
320 entry.rev - 1 |
|
321 }; |
|
322 delta_chain.push(entry); |
|
323 entry = self.revlog.get_entry_internal(base_rev)?; |
|
324 } |
|
325 |
|
326 // TODO do not look twice in the index |
|
327 let index_entry = self |
|
328 .revlog |
|
329 .index |
|
330 .get_entry(self.rev) |
|
331 .ok_or(RevlogError::InvalidRevision)?; |
|
332 |
|
333 let data = if delta_chain.is_empty() { |
|
334 entry.data_chunk()? |
|
335 } else { |
|
336 Revlog::build_data_from_deltas(entry, &delta_chain)?.into() |
|
337 }; |
|
338 |
|
339 if self.revlog.check_hash( |
|
340 index_entry.p1(), |
|
341 index_entry.p2(), |
|
342 index_entry.hash().as_bytes(), |
|
343 &data, |
|
344 ) { |
|
345 Ok(data) |
|
346 } else { |
|
347 Err(RevlogError::corrupted()) |
|
348 } |
|
349 } |
|
350 |
341 /// Extract the data contained in the entry. |
351 /// Extract the data contained in the entry. |
342 /// This may be a delta. (See `is_delta`.) |
352 /// This may be a delta. (See `is_delta`.) |
343 fn data_chunk(&self) -> Result<Cow<'_, [u8]>, RevlogError> { |
353 fn data_chunk(&self) -> Result<Cow<'a, [u8]>, RevlogError> { |
344 if self.bytes.is_empty() { |
354 if self.bytes.is_empty() { |
345 return Ok(Cow::Borrowed(&[])); |
355 return Ok(Cow::Borrowed(&[])); |
346 } |
356 } |
347 match self.bytes[0] { |
357 match self.bytes[0] { |
348 // Revision data is the entirety of the entry, including this |
358 // Revision data is the entirety of the entry, including this |