This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / knot2 / third_party / gix-pack / src / data / mod.rs
5.6 kB 171 lines
1//! a pack data file 2use std::path::Path; 3 4/// The offset to an entry into the pack data file, relative to its beginning. 5pub type Offset = u64; 6 7/// An identifier to uniquely identify all packs loaded within a known context or namespace. 8pub type Id = u32; 9 10/// An representing an full- or delta-object within a pack 11#[derive(PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone)] 12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 13pub struct Entry { 14 /// The entry's header 15 pub header: entry::Header, 16 /// The decompressed size of the entry in bytes. 17 /// 18 /// Note that for non-delta entries this will be the size of the object itself. 19 pub decompressed_size: u64, 20 /// absolute offset to compressed object data in the pack, just behind the entry's header 21 pub data_offset: Offset, 22} 23 24mod file; 25pub use file::{Header, decode, verify}; 26/// 27pub mod header; 28 29/// 30pub mod init { 31 pub use super::header::decode::Error; 32} 33 34/// 35pub mod entry; 36 37/// 38#[cfg(feature = "streaming-input")] 39pub mod input; 40 41/// Utilities to encode pack data entries and write them to a `Write` implementation to resemble a pack data file. 42#[cfg(feature = "generate")] 43pub mod output; 44 45/// A slice into a pack file denoting a pack entry. 46/// 47/// An entry can be decoded into an object. 48pub type EntryRange = std::ops::Range<Offset>; 49 50/// Supported versions of a pack data file 51#[derive(Default, PartialEq, Eq, Debug, Hash, Ord, PartialOrd, Clone, Copy)] 52#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 53pub enum Version { 54 /// The default pack data version. 55 /// 56 /// This is the version generated by Git and by `gix-pack` writers. 57 #[default] 58 V2, 59 /// A pack data version accepted by Git and recognized by `gix-pack` readers. 60 /// 61 /// Git does not generate this version, and `gix-pack` writers currently reject it. 62 /// Entries are decoded with the same layout as [`V2`](Version::V2); the difference 63 /// visible to this crate is the version number stored in the pack header. 64 V3, 65} 66 67/// A pack data file, read from disk on demand rather than held in memory. 68#[allow(missing_docs)] 69pub struct File { 70 file: std::fs::File, 71 len: usize, 72 path: std::path::PathBuf, 73 pub id: Id, 74 version: Version, 75 num_objects: u32, 76 hash_len: usize, 77 object_hash: gix_hash::Kind, 78 alloc_limit_bytes: Option<usize>, 79} 80 81/// Information about the pack data file itself 82impl File { 83 /// The pack data version of this file 84 pub fn version(&self) -> Version { 85 self.version 86 } 87 /// The number of objects stored in this pack data file 88 pub fn num_objects(&self) -> u32 { 89 self.num_objects 90 } 91 /// The length of all pack data, including the pack header and the pack trailer 92 pub fn data_len(&self) -> usize { 93 self.len 94 } 95 /// The kind of hash we use internally. 96 pub fn object_hash(&self) -> gix_hash::Kind { 97 self.object_hash 98 } 99 /// The maximum size of a single allocation caused by user-controlled on-disk pack data. 100 /// 101 /// A value of `None` means no additional limit is enforced. 102 pub fn alloc_limit_bytes(&self) -> Option<usize> { 103 self.alloc_limit_bytes 104 } 105 /// The position of the byte one past the last pack entry, or in other terms, the first byte of the trailing hash. 106 pub fn pack_end(&self) -> usize { 107 self.len - self.hash_len 108 } 109 110 /// The path to the pack data file on disk 111 pub fn path(&self) -> &Path { 112 &self.path 113 } 114 115 pub(crate) fn read_exact_at(&self, offset: usize, buf: &mut [u8]) -> std::io::Result<()> { 116 use std::os::unix::fs::FileExt; 117 self.file.read_exact_at(buf, offset as u64) 118 } 119 120 pub(crate) fn read_span(&self, slice: EntryRange) -> Option<Vec<u8>> { 121 let start = usize::try_from(slice.start).ok()?; 122 let end = usize::try_from(slice.end).ok()?; 123 if start > end || end > self.len { 124 return None; 125 } 126 let mut buf = vec![0u8; end - start]; 127 self.read_exact_at(start, &mut buf).ok()?; 128 Some(buf) 129 } 130 131 #[allow(missing_docs)] 132 pub fn read_into(&self, slice: EntryRange, buf: &mut Vec<u8>) -> bool { 133 let (Ok(start), Ok(end)) = (usize::try_from(slice.start), usize::try_from(slice.end)) 134 else { 135 return false; 136 }; 137 if start > end || end > self.len { 138 return false; 139 } 140 buf.clear(); 141 buf.resize(end - start, 0); 142 self.read_exact_at(start, buf).is_ok() 143 } 144 145 pub(crate) fn materialized(&self) -> std::io::Result<crate::MMap> { 146 crate::MMap::map(&self.file) 147 } 148 149 /// Returns the pack data at the given slice if its range is contained in the pack data. 150 pub fn entry_slice(&self, slice: EntryRange) -> Option<Vec<u8>> { 151 self.read_span(slice) 152 } 153 154 /// Returns the CRC32 of the pack data indicated by `pack_offset` and the `size` of the data. 155 /// 156 /// _Note:_ finding the right size is only possible by decompressing 157 /// the pack entry beforehand, or by using the (to be sorted) offsets stored in an index file. 158 /// 159 /// # Panics 160 /// 161 /// If `pack_offset` or `size` are pointing to a range outside of the pack data. 162 pub fn entry_crc32(&self, pack_offset: Offset, size: usize) -> u32 { 163 let buf = self 164 .read_span(pack_offset..pack_offset + size as u64) 165 .expect("entry range within pack data"); 166 gix_features::hash::crc32(&buf) 167 } 168} 169 170/// 171pub mod delta;