mirror of
https://github.com/facebook/sapling.git
synced 2024-10-10 16:57:49 +03:00
blobrepo: optionally verify that provided and computed entry hashes are consistent
Summary: We know that the hashes for non-root-tree-manifests and filenodes should always be consistent. Verify that. Reviewed By: farnz Differential Revision: D7704087 fbshipit-source-id: 7f6207878c5cd372b272aa6970506dd63b5a3c7c
This commit is contained in:
parent
9b5ee510cb
commit
c652345586
@ -63,4 +63,7 @@ pub enum ErrorKind {
|
||||
#[fail(display = "DParents failed to complete")] ParentsFailed,
|
||||
#[fail(display = "Expected {} to be a manifest, found a {} instead", _0, _1)]
|
||||
NotAManifest(DNodeHash, Type),
|
||||
#[fail(display = "Inconsistent node hash for entry: path {}, provided: {}, computed: {}", _0,
|
||||
_1, _2)]
|
||||
InconsistentEntryHash(RepoPath, HgNodeHash, HgNodeHash),
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ use heads::Heads;
|
||||
use manifoldblob::ManifoldBlob;
|
||||
use memblob::EagerMemblob;
|
||||
use memheads::MemHeads;
|
||||
use mercurial::{HgNodeHash, HgParents};
|
||||
use mercurial::{HgBlobNode, HgNodeHash, HgParents};
|
||||
use mercurial_types::{Changeset, DChangesetId, DFileNodeId, DNodeHash, DParents, Entry, HgBlob,
|
||||
Manifest, RepoPath, RepositoryId};
|
||||
use mercurial_types::manifest;
|
||||
@ -377,7 +377,6 @@ impl BlobRepo {
|
||||
|
||||
/// Context for uploading a Mercurial entry.
|
||||
pub struct UploadHgEntry {
|
||||
// XXX optionally verify that the hash actually matches the contents
|
||||
/// This hash is used as the blobstore key, even if it doesn't match the hash of the
|
||||
/// parents and raw content. This is done because in some cases like root tree manifests
|
||||
/// in hybrid mode, Mercurial sends fake hashes.
|
||||
@ -387,6 +386,8 @@ pub struct UploadHgEntry {
|
||||
pub p1: Option<HgNodeHash>,
|
||||
pub p2: Option<HgNodeHash>,
|
||||
pub path: RepoPath,
|
||||
/// Pass `true` here to verify that the hash actually matches the inputs.
|
||||
pub check_nodeid: bool,
|
||||
}
|
||||
|
||||
impl UploadHgEntry {
|
||||
@ -408,13 +409,25 @@ impl UploadHgEntry {
|
||||
p1,
|
||||
p2,
|
||||
path,
|
||||
check_nodeid,
|
||||
} = self;
|
||||
|
||||
let p1 = p1.as_ref();
|
||||
let p2 = p2.as_ref();
|
||||
let raw_content = raw_content.clean();
|
||||
|
||||
// XXX verify nodeid here
|
||||
if check_nodeid {
|
||||
let computed_nodeid = HgBlobNode::new(raw_content.clone(), p1, p2)
|
||||
.nodeid()
|
||||
.expect("raw_content must have data available");
|
||||
if nodeid != computed_nodeid {
|
||||
bail_err!(ErrorKind::InconsistentEntryHash(
|
||||
path,
|
||||
nodeid,
|
||||
computed_nodeid
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let parents = HgParents::new(p1, p2);
|
||||
|
||||
|
@ -161,6 +161,7 @@ fn upload_hg_entry(
|
||||
p1,
|
||||
p2,
|
||||
path,
|
||||
check_nodeid: true,
|
||||
};
|
||||
upload.upload(repo).unwrap()
|
||||
}
|
||||
|
@ -57,6 +57,7 @@ impl UploadableHgBlob for Filelog {
|
||||
p1: self.p1,
|
||||
p2: self.p2,
|
||||
path: node_key.path.clone(),
|
||||
check_nodeid: true,
|
||||
};
|
||||
upload
|
||||
.upload(repo)
|
||||
|
@ -100,6 +100,9 @@ impl UploadableHgBlob for TreemanifestEntry {
|
||||
p1: self.p1,
|
||||
p2: self.p2,
|
||||
path: node_key.path.clone(),
|
||||
// The root tree manifest is expected to have the wrong hash in hybrid mode.
|
||||
// XXX possibly remove this once hybrid mode is gone
|
||||
check_nodeid: !node_key.path.is_root(),
|
||||
};
|
||||
upload.upload(repo).map(move |(_node, value)| {
|
||||
(
|
||||
|
@ -179,6 +179,7 @@ fn upload_entry(
|
||||
p1: p1.cloned(),
|
||||
p2: p2.cloned(),
|
||||
path,
|
||||
check_nodeid: true,
|
||||
};
|
||||
upload.upload(&blobrepo)
|
||||
})
|
||||
@ -319,6 +320,10 @@ fn main() {
|
||||
p1,
|
||||
p2,
|
||||
path: RepoPath::root(),
|
||||
// The root tree manifest is expected to have the wrong hash in hybrid
|
||||
// mode. This will probably never go away for compatibility with
|
||||
// old repositories.
|
||||
check_nodeid: false,
|
||||
};
|
||||
upload.upload(&blobrepo)
|
||||
}
|
||||
|
@ -59,6 +59,33 @@ impl RepoPath {
|
||||
Ok(RepoPath::FilePath(path))
|
||||
}
|
||||
|
||||
/// Whether this path represents the root.
|
||||
#[inline]
|
||||
pub fn is_root(&self) -> bool {
|
||||
match *self {
|
||||
RepoPath::RootPath => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this path represents a directory that isn't the root.
|
||||
#[inline]
|
||||
pub fn is_dir(&self) -> bool {
|
||||
match *self {
|
||||
RepoPath::DirectoryPath(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this path represents a file.
|
||||
#[inline]
|
||||
pub fn is_file(&self) -> bool {
|
||||
match *self {
|
||||
RepoPath::FilePath(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the length of this repo path in bytes. `RepoPath::Root` has length 0.
|
||||
pub fn len(&self) -> usize {
|
||||
match *self {
|
||||
|
Loading…
Reference in New Issue
Block a user