##// END OF EJS Templates
rhg: Expose FilelogEntry that wraps RevlogEntry...
Simon Sapin -
r49374:35c47015 default
parent child Browse files
Show More
@@ -1,6 +1,7
1 1 use crate::errors::HgError;
2 2 use crate::repo::Repo;
3 3 use crate::revlog::path_encode::path_encode;
4 use crate::revlog::revlog::RevlogEntry;
4 5 use crate::revlog::revlog::{Revlog, RevlogError};
5 6 use crate::revlog::NodePrefix;
6 7 use crate::revlog::Revision;
@@ -23,7 +24,7 impl Filelog {
23 24 Ok(Self { revlog })
24 25 }
25 26
26 /// The given node ID is that of the file as found in a manifest, not of a
27 /// The given node ID is that of the file as found in a filelog, not of a
27 28 /// changeset.
28 29 pub fn data_for_node(
29 30 &self,
@@ -33,7 +34,7 impl Filelog {
33 34 self.data_for_rev(file_rev)
34 35 }
35 36
36 /// The given revision is that of the file as found in a manifest, not of a
37 /// The given revision is that of the file as found in a filelog, not of a
37 38 /// changeset.
38 39 pub fn data_for_rev(
39 40 &self,
@@ -42,6 +43,25 impl Filelog {
42 43 let data: Vec<u8> = self.revlog.get_rev_data(file_rev)?.into_owned();
43 44 Ok(FilelogRevisionData(data.into()))
44 45 }
46
47 /// The given node ID is that of the file as found in a filelog, not of a
48 /// changeset.
49 pub fn entry_for_node(
50 &self,
51 file_node: impl Into<NodePrefix>,
52 ) -> Result<FilelogEntry, RevlogError> {
53 let file_rev = self.revlog.rev_from_node(file_node.into())?;
54 self.entry_for_rev(file_rev)
55 }
56
57 /// The given revision is that of the file as found in a filelog, not of a
58 /// changeset.
59 pub fn entry_for_rev(
60 &self,
61 file_rev: Revision,
62 ) -> Result<FilelogEntry, RevlogError> {
63 Ok(FilelogEntry(self.revlog.get_entry(file_rev)?))
64 }
45 65 }
46 66
47 67 fn store_path(hg_path: &HgPath, suffix: &[u8]) -> PathBuf {
@@ -50,6 +70,14 fn store_path(hg_path: &HgPath, suffix:
50 70 get_path_from_bytes(&encoded_bytes).into()
51 71 }
52 72
73 pub struct FilelogEntry<'a>(RevlogEntry<'a>);
74
75 impl FilelogEntry<'_> {
76 pub fn data(&self) -> Result<FilelogRevisionData, HgError> {
77 Ok(FilelogRevisionData(self.0.data()?.into_owned()))
78 }
79 }
80
53 81 /// The data for one revision in a filelog, uncompressed and delta-resolved.
54 82 pub struct FilelogRevisionData(Vec<u8>);
55 83
@@ -39,9 +39,13 impl From<NodeMapError> for RevlogError
39 39 }
40 40 }
41 41
42 fn corrupted() -> HgError {
43 HgError::corrupted("corrupted revlog")
44 }
45
42 46 impl RevlogError {
43 47 fn corrupted() -> Self {
44 RevlogError::Other(HgError::corrupted("corrupted revlog"))
48 RevlogError::Other(corrupted())
45 49 }
46 50 }
47 51
@@ -191,7 +195,7 impl Revlog {
191 195 if rev == NULL_REVISION {
192 196 return Ok(Cow::Borrowed(&[]));
193 197 };
194 self.get_entry(rev)?.data()
198 Ok(self.get_entry(rev)?.data()?)
195 199 }
196 200
197 201 /// Check the hash of some given data against the recorded hash.
@@ -222,13 +226,13 impl Revlog {
222 226 fn build_data_from_deltas(
223 227 snapshot: RevlogEntry,
224 228 deltas: &[RevlogEntry],
225 ) -> Result<Vec<u8>, RevlogError> {
229 ) -> Result<Vec<u8>, HgError> {
226 230 let snapshot = snapshot.data_chunk()?;
227 231 let deltas = deltas
228 232 .iter()
229 233 .rev()
230 234 .map(RevlogEntry::data_chunk)
231 .collect::<Result<Vec<Cow<'_, [u8]>>, RevlogError>>()?;
235 .collect::<Result<Vec<_>, _>>()?;
232 236 let patches: Vec<_> =
233 237 deltas.iter().map(|d| patch::PatchList::new(d)).collect();
234 238 let patch = patch::fold_patch_lists(&patches);
@@ -246,7 +250,10 impl Revlog {
246 250 }
247 251
248 252 /// Get an entry of the revlog.
249 fn get_entry(&self, rev: Revision) -> Result<RevlogEntry, RevlogError> {
253 pub fn get_entry(
254 &self,
255 rev: Revision,
256 ) -> Result<RevlogEntry, RevlogError> {
250 257 let index_entry = self
251 258 .index
252 259 .get_entry(rev)
@@ -281,8 +288,8 impl Revlog {
281 288 fn get_entry_internal(
282 289 &self,
283 290 rev: Revision,
284 ) -> Result<RevlogEntry, RevlogError> {
285 return self.get_entry(rev).map_err(|_| RevlogError::corrupted());
291 ) -> Result<RevlogEntry, HgError> {
292 return self.get_entry(rev).map_err(|_| corrupted());
286 293 }
287 294 }
288 295
@@ -304,7 +311,7 impl<'a> RevlogEntry<'a> {
304 311 }
305 312
306 313 /// The data for this entry, after resolving deltas if any.
307 pub fn data(&self) -> Result<Cow<'a, [u8]>, RevlogError> {
314 pub fn data(&self) -> Result<Cow<'a, [u8]>, HgError> {
308 315 let mut entry = self.clone();
309 316 let mut delta_chain = vec![];
310 317
@@ -328,7 +335,7 impl<'a> RevlogEntry<'a> {
328 335 .revlog
329 336 .index
330 337 .get_entry(self.rev)
331 .ok_or(RevlogError::InvalidRevision)?;
338 .ok_or_else(corrupted)?;
332 339
333 340 let data = if delta_chain.is_empty() {
334 341 entry.data_chunk()?
@@ -344,13 +351,13 impl<'a> RevlogEntry<'a> {
344 351 ) {
345 352 Ok(data)
346 353 } else {
347 Err(RevlogError::corrupted())
354 Err(corrupted())
348 355 }
349 356 }
350 357
351 358 /// Extract the data contained in the entry.
352 359 /// This may be a delta. (See `is_delta`.)
353 fn data_chunk(&self) -> Result<Cow<'a, [u8]>, RevlogError> {
360 fn data_chunk(&self) -> Result<Cow<'a, [u8]>, HgError> {
354 361 if self.bytes.is_empty() {
355 362 return Ok(Cow::Borrowed(&[]));
356 363 }
@@ -365,39 +372,35 impl<'a> RevlogEntry<'a> {
365 372 // zstd data.
366 373 b'\x28' => Ok(Cow::Owned(self.uncompressed_zstd_data()?)),
367 374 // A proper new format should have had a repo/store requirement.
368 _format_type => Err(RevlogError::corrupted()),
375 _format_type => Err(corrupted()),
369 376 }
370 377 }
371 378
372 fn uncompressed_zlib_data(&self) -> Result<Vec<u8>, RevlogError> {
379 fn uncompressed_zlib_data(&self) -> Result<Vec<u8>, HgError> {
373 380 let mut decoder = ZlibDecoder::new(self.bytes);
374 381 if self.is_delta() {
375 382 let mut buf = Vec::with_capacity(self.compressed_len);
376 decoder
377 .read_to_end(&mut buf)
378 .map_err(|_| RevlogError::corrupted())?;
383 decoder.read_to_end(&mut buf).map_err(|_| corrupted())?;
379 384 Ok(buf)
380 385 } else {
381 386 let mut buf = vec![0; self.uncompressed_len];
382 decoder
383 .read_exact(&mut buf)
384 .map_err(|_| RevlogError::corrupted())?;
387 decoder.read_exact(&mut buf).map_err(|_| corrupted())?;
385 388 Ok(buf)
386 389 }
387 390 }
388 391
389 fn uncompressed_zstd_data(&self) -> Result<Vec<u8>, RevlogError> {
392 fn uncompressed_zstd_data(&self) -> Result<Vec<u8>, HgError> {
390 393 if self.is_delta() {
391 394 let mut buf = Vec::with_capacity(self.compressed_len);
392 395 zstd::stream::copy_decode(self.bytes, &mut buf)
393 .map_err(|_| RevlogError::corrupted())?;
396 .map_err(|_| corrupted())?;
394 397 Ok(buf)
395 398 } else {
396 399 let mut buf = vec![0; self.uncompressed_len];
397 400 let len = zstd::block::decompress_to_buffer(self.bytes, &mut buf)
398 .map_err(|_| RevlogError::corrupted())?;
401 .map_err(|_| corrupted())?;
399 402 if len != self.uncompressed_len {
400 Err(RevlogError::corrupted())
403 Err(corrupted())
401 404 } else {
402 405 Ok(buf)
403 406 }
@@ -512,17 +512,18 fn unsure_is_modified(
512 512 }
513 513 let filelog = repo.filelog(hg_path)?;
514 514 let fs_len = fs_metadata.len();
515 let filelog_entry =
516 filelog.entry_for_node(entry.node_id()?).map_err(|_| {
517 HgError::corrupted("filelog missing node from manifest")
518 })?;
515 519 // TODO: check `fs_len` here like below, but based on
516 520 // `RevlogEntry::uncompressed_len` without decompressing the full filelog
517 521 // contents where possible. This is only valid if the revlog data does not
518 522 // contain metadata. See how Python’s `revlog.rawsize` calls
519 523 // `storageutil.filerevisioncopied`.
520 524 // (Maybe also check for content-modifying flags? See `revlog.size`.)
521 let filelog_entry =
522 filelog.data_for_node(entry.node_id()?).map_err(|_| {
523 HgError::corrupted("filelog missing node from manifest")
524 })?;
525 let contents_in_p1 = filelog_entry.file_data()?;
525 let filelog_data = filelog_entry.data()?;
526 let contents_in_p1 = filelog_data.file_data()?;
526 527 if contents_in_p1.len() as u64 != fs_len {
527 528 // No need to read the file contents:
528 529 // it cannot be equal if it has a different length.
General Comments 0
You need to be logged in to leave comments. Login now