Skip to content

Commit

Permalink
Support for verifying pack files and index files
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Jun 25, 2020
1 parent 4a153da commit b09b4e1
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 15 deletions.
51 changes: 41 additions & 10 deletions git-odb/src/pack/index/file.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::pack;
use byteorder::{BigEndian, ByteOrder};
use filebuffer::FileBuffer;
use git_object::{self as object, SHA1_SIZE};
Expand Down Expand Up @@ -54,6 +55,14 @@ quick_error! {
Mismatch { expected: object::Id, actual: object::Id } {
display("index checksum mismatch: expected {}, got {}", expected, actual)
}
PackChecksum (err: pack::ChecksumError) {
display("The pack of this index file failed to verify its checksums")
from()
cause(err)
}
PackMismatch { expected: object::Id, actual: object::Id } {
display("The packfiles checksum didn't match the index file checksum: expected {}, got {}", expected, actual)
}
}
}

Expand All @@ -78,17 +87,39 @@ impl File {
pub fn checksum_of_index(&self) -> object::Id {
object::Id::from_20_bytes(&self.data[self.data.len() - SHA1_SIZE..])
}

/// If `pack` is provided, it is expected (and validated to be) the pack belonging to this index.
/// It will be used to validate internal integrity of the pack before checking each objects integrity
/// is indeed as advertised via its SHA1 as stored in this index, as well as the CRC hash.
#[cfg(any(feature = "fast-sha1", feature = "minimal-sha1"))]
pub fn verify_checksum_of_index(&self) -> Result<object::Id, ChecksumError> {
let mut hasher = crate::sha1::Sha1::default();
hasher.update(&self.data[..self.data.len() - SHA1_SIZE]);
let actual = hasher.digest();

let expected = self.checksum_of_index();
if actual == expected {
Ok(actual)
} else {
Err(ChecksumError::Mismatch { actual, expected })
pub fn verify_checksum_of_index(
&self,
pack: Option<&pack::File>,
) -> Result<object::Id, ChecksumError> {
let verify_self = || {
let mut hasher = crate::sha1::Sha1::default();
hasher.update(&self.data[..self.data.len() - SHA1_SIZE]);
let actual = hasher.digest();

let expected = self.checksum_of_index();
if actual == expected {
Ok(actual)
} else {
Err(ChecksumError::Mismatch { actual, expected })
}
};
match pack {
None => verify_self(),
Some(pack) => {
if self.checksum_of_pack() != pack.checksum() {
return Err(ChecksumError::PackMismatch {
actual: pack.checksum(),
expected: self.checksum_of_pack(),
});
}
pack.verify_checksum()?;
verify_self()
}
}
}

Expand Down
6 changes: 5 additions & 1 deletion git-odb/tests/pack/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fn pack_lookup() {
assert_eq!(pack.kind(), pack::Kind::V2);
assert_eq!(pack.num_objects(), idx.num_objects());
assert_eq!(
idx.verify_checksum_of_index().unwrap(),
idx.verify_checksum_of_index(Some(&pack)).unwrap(),
idx.checksum_of_index()
);
for idx_entry in idx.iter() {
Expand Down Expand Up @@ -66,6 +66,10 @@ fn iter() {
assert_eq!(idx.kind(), *kind);
assert_eq!(idx.version(), *version);
assert_eq!(idx.num_objects(), *num_objects);
assert_eq!(
idx.verify_checksum_of_index(None).unwrap(),
idx.checksum_of_index()
);
assert_eq!(idx.checksum_of_index(), hex_to_id(index_checksum));
assert_eq!(idx.checksum_of_pack(), hex_to_id(pack_checksum));
assert_eq!(idx.iter().count(), *num_objects as usize);
Expand Down
15 changes: 13 additions & 2 deletions gitoxide-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ pub fn init() -> Result<()> {
git_repository::init::repository().with_context(|| "Repository initialization failed")
}

pub fn verify_pack_or_pack_index(path: impl AsRef<Path>, mut out: impl io::Write) -> Result<()> {
pub fn verify_pack_or_pack_index(
path: impl AsRef<Path>,
mut out: impl io::Write,
mut err: impl io::Write,
) -> Result<()> {
let path = path.as_ref();
let ext = path.extension()
.and_then(|ext| ext.to_str())
Expand All @@ -18,7 +22,14 @@ pub fn verify_pack_or_pack_index(path: impl AsRef<Path>, mut out: impl io::Write
"idx" => {
let idx = git_odb::pack::index::File::at(path)
.with_context(|| "Could not open pack index file")?;
idx.verify_checksum_of_index()?;
let packfile_path = path.with_extension("pack");
let pack = git_odb::pack::File::at(&packfile_path)
.or_else(|e| {
writeln!(err, "Could not find matching pack file at '{}' - only index file will be verified, error was: {}", packfile_path.display(), e).ok();
Err(e)
})
.ok();
idx.verify_checksum_of_index(pack.as_ref())?;
}
ext => {
return Err(anyhow!(
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use anyhow::Result;
use gitoxide_core as core;
use std::io::stdout;
use std::io::{stderr, stdout};
use structopt::StructOpt;

mod options {
Expand Down Expand Up @@ -53,7 +53,7 @@ fn main() -> Result<()> {
options::Subcommands::Init => core::init(),
options::Subcommands::Plumbing(cmd) => match cmd {
options::Plumbing::VerifyPack { path } => {
core::verify_pack_or_pack_index(path, stdout())
core::verify_pack_or_pack_index(path, stdout(), stderr())
}
},
}?;
Expand Down

0 comments on commit b09b4e1

Please sign in to comment.