diff --git a/git-chunk/src/lib.rs b/git-chunk/src/lib.rs index 64bf204bed..12682866fc 100644 --- a/git-chunk/src/lib.rs +++ b/git-chunk/src/lib.rs @@ -17,6 +17,31 @@ pub mod file { use crate::file::Index; use std::ops::Range; + /// + pub mod not_found { + use std::fmt::{Display, Formatter}; + + /// The error returned by [Index::offset_by_kind()][super::Index::offset_by_kind()]. + #[allow(missing_docs)] + #[derive(Debug)] + pub struct Error { + pub kind: crate::Kind, + pub name: &'static str, + } + + impl Display for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "Chunk named {:?} (id = {}) was not found in chunk file index", + self.name, self.kind + ) + } + } + + impl std::error::Error for Error {} + } + /// An entry of a chunk file index pub struct Entry { /// The kind of the chunk file @@ -32,10 +57,15 @@ pub mod file { pub const EMPTY_SIZE: usize = Index::ENTRY_SIZE; /// Find a chunk of `kind` and return its offset into the data if found - pub fn offset_by_kind(&self, kind: crate::Kind) -> Option> { + pub fn offset_by_kind( + &self, + kind: crate::Kind, + name: &'static str, + ) -> Result, not_found::Error> { self.chunks .iter() .find_map(|c| (c.kind == kind).then(|| c.offset.clone())) + .ok_or_else(|| not_found::Error { kind, name }) } } } diff --git a/git-pack/src/multi_index.rs b/git-pack/src/multi_index.rs index 124c691c41..b2c15d0500 100644 --- a/git-pack/src/multi_index.rs +++ b/git-pack/src/multi_index.rs @@ -1,5 +1,7 @@ #![allow(missing_docs, unused)] + use filebuffer::FileBuffer; +use std::ops::Range; /// Known multi-index file versions #[derive(PartialEq, Eq, Ord, PartialOrd, Debug, Hash, Clone, Copy)] @@ -25,6 +27,7 @@ pub struct File { num_chunks: u8, /// The amount of pack files contained within num_packs: u32, + fanout: Range, } /// @@ -41,9 +44,27 @@ pub mod access { } } +mod chunk { + pub mod pack_names { + pub const ID: git_chunk::Kind = 0x504e414d; /* "PNAM" */ + } + pub mod fanout { + pub const ID: git_chunk::Kind = 0x4f494446; /* "OIDF" */ + } + pub mod lookup { + pub const ID: git_chunk::Kind = 0x4f49444c; /* "OIDL" */ + } + pub mod offsets { + pub const ID: git_chunk::Kind = 0x4f4f4646; /* "OOFF" */ + } + pub mod large_offsets { + pub const ID: git_chunk::Kind = 0x4c4f4646; /* "LOFF" */ + } +} + /// pub mod init { - use crate::multi_index::{File, Version}; + use crate::multi_index::{chunk, File, Version}; use byteorder::{BigEndian, ByteOrder, ReadBytesExt}; use filebuffer::FileBuffer; use std::convert::{TryFrom, TryInto}; @@ -65,6 +86,8 @@ pub mod init { UnsupportedHashKind { kind: u8 }, #[error(transparent)] ChunkFileDecode(#[from] git_chunk::file::decode::Error), + #[error(transparent)] + MissingChunk(#[from] git_chunk::file::index::not_found::Error), } } pub use error::Error; @@ -128,12 +151,18 @@ pub mod init { }; let chunks = git_chunk::file::Index::from_bytes(&data, HEADER_LEN, num_chunks as u32)?; + let pack_names = chunks.offset_by_kind(chunk::pack_names::ID, "PNAM")?; + let fanout = chunks.offset_by_kind(chunk::fanout::ID, "OIDF")?; + let lookup = chunks.offset_by_kind(chunk::lookup::ID, "OIDL")?; + let offsets = chunks.offset_by_kind(chunk::offsets::ID, "OOFF")?; + let large_offsets = chunks.offset_by_kind(chunk::large_offsets::ID, "LOFF").ok(); Ok(File { data, path: path.to_owned(), version, hash_kind, + fanout, num_chunks, num_packs, })