Commit caafdc0d authored by Arseniy Alekseyev's avatar Arseniy Alekseyev
Browse files

rhg: handle null changelog and manifest revisions

Differential Revision: https://phab.mercurial-scm.org/D11650
parent 63e86fc9bfec
Pipeline #27697 failed with stages
in 51 minutes and 58 seconds
use crate::errors::HgError;
use crate::repo::Repo;
use crate::revlog::node::NULL_NODE;
use crate::revlog::revlog::{Revlog, RevlogError};
use crate::revlog::Revision;
use crate::revlog::{Node, NodePrefix};
......@@ -58,10 +59,9 @@ impl ChangelogEntry {
/// Return the node id of the `manifest` referenced by this `changelog`
/// entry.
pub fn manifest_node(&self) -> Result<Node, HgError> {
Node::from_hex_for_repo(
self.lines()
.next()
.ok_or_else(|| HgError::corrupted("empty changelog entry"))?,
)
match self.lines().next() {
None => Ok(NULL_NODE),
Some(x) => Node::from_hex_for_repo(x),
}
}
}
......@@ -208,6 +208,9 @@ impl<'a> IndexEntry<'a> {
/// Value of the inline flag.
pub fn is_inline(index_bytes: &[u8]) -> bool {
if index_bytes.len() < 4 {
return true;
}
match &index_bytes[0..=1] {
[0, 0] | [0, 2] => false,
_ => true,
......
......@@ -72,7 +72,7 @@ impl Revlog {
let index_path = index_path.as_ref();
let index_mmap = repo.store_vfs().mmap_open(&index_path)?;
let version = get_version(&index_mmap);
let version = get_version(&index_mmap)?;
if version != 1 {
// A proper new version should have had a repo/store requirement.
return Err(HgError::corrupted("corrupted revlog"));
......@@ -179,6 +179,9 @@ impl Revlog {
/// snapshot to rebuild the final data.
#[timed]
pub fn get_rev_data(&self, rev: Revision) -> Result<Vec<u8>, RevlogError> {
if rev == NULL_REVISION {
return Ok(vec![]);
};
// Todo return -> Cow
let mut entry = self.get_entry(rev)?;
let mut delta_chain = vec![];
......@@ -371,8 +374,16 @@ impl<'a> RevlogEntry<'a> {
}
/// Format version of the revlog.
pub fn get_version(index_bytes: &[u8]) -> u16 {
BigEndian::read_u16(&index_bytes[2..=3])
pub fn get_version(index_bytes: &[u8]) -> Result<u16, HgError> {
if index_bytes.len() == 0 {
return Ok(1);
};
if index_bytes.len() < 4 {
return Err(HgError::corrupted(
"corrupted revlog: can't read the index format header",
));
};
Ok(BigEndian::read_u16(&index_bytes[2..=3]))
}
/// Calculate the hash of a revision given its data and its parents.
......
Create a repo such that the changelog entry refers to a null manifest node:
$ hg init a
$ cd a
$ hg log
$ touch x
$ hg add x
$ hg commit -m "init"
$ hg rm x
$ hg commit -q --amend
$ wc -c < .hg/store/00manifest.i
0
Make sure that the manifest can be read (and is empty):
$ hg --config rhg.on-unsupported=abort files -r .
[1]
Test a null changelog rev, too:
$ hg --config rhg.on-unsupported=abort files -r 0000000000000000000000000000000000000000
[1]
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment