gix_pack/data/file/init.rs
1use std::path::{Path, PathBuf};
2
3use crate::data;
4
5/// Instantiation
6impl data::File<crate::MMap> {
7 /// Try opening a data file at the given `path`.
8 ///
9 /// The `object_hash` is a way to read (and write) the same file format with different hashes, as the hash kind
10 /// isn't stored within the file format itself.
11 ///
12 /// This constructor leaves allocation limiting disabled, allowing allocations of any size dictated by pack data.
13 /// Use [`Self::from_data()`] together with [`File::with_alloc_limit_bytes()`][crate::data::File::with_alloc_limit_bytes()]
14 /// when working with untrusted input.
15 pub fn at(path: impl AsRef<Path>, object_hash: gix_hash::Kind) -> Result<Self, data::header::decode::Error> {
16 Self::at_inner(path.as_ref(), object_hash)
17 }
18
19 fn at_inner(path: &Path, object_hash: gix_hash::Kind) -> Result<Self, data::header::decode::Error> {
20 let data = crate::mmap::read_only(path).map_err(|e| data::header::decode::Error::Io {
21 source: e,
22 path: path.to_owned(),
23 })?;
24 Self::from_data(data, path.to_owned(), object_hash)
25 }
26}
27
28impl<T> data::File<T>
29where
30 T: crate::FileData,
31{
32 /// Instantiate a data file from `data` as assumed to be read or memory-mapped from `path`.
33 ///
34 /// This constructor leaves allocation limiting disabled, allowing allocations of any size dictated by pack data.
35 /// Call [`File::with_alloc_limit_bytes()`][crate::data::File::with_alloc_limit_bytes()] before decoding entries from untrusted input.
36 pub fn from_data(data: T, path: PathBuf, object_hash: gix_hash::Kind) -> Result<Self, data::header::decode::Error> {
37 use crate::data::header::N32_SIZE;
38 let hash_len = object_hash.len_in_bytes();
39 let pack_len = data.len();
40 let id = gix_features::hash::crc32(path.as_os_str().to_string_lossy().as_bytes());
41 if pack_len < N32_SIZE * 3 + hash_len {
42 return Err(data::header::decode::Error::Corrupt(format!(
43 "Pack data of size {pack_len} is too small for even an empty pack with shortest hash"
44 )));
45 }
46 let (kind, num_objects) =
47 data::header::decode(&data[..12].try_into().expect("enough data after previous check"))?;
48 Ok(Self {
49 data,
50 path,
51 id,
52 version: kind,
53 num_objects,
54 hash_len,
55 object_hash,
56 alloc_limit_bytes: None,
57 })
58 }
59
60 /// Configure the maximum size of a single allocation caused by user-controlled on-disk pack data.
61 ///
62 /// Use `None` to disable the limit, which is also the default.
63 ///
64 /// This is currently enforced when decoding pack entries and resolving delta chains.
65 /// Callers that allocate from pack metadata directly should consult [`File::alloc_limit_bytes()`][crate::data::File::alloc_limit_bytes()]
66 /// and apply the same limit themselves.
67 pub fn with_alloc_limit_bytes(mut self, alloc_limit_bytes: Option<usize>) -> Self {
68 self.alloc_limit_bytes = alloc_limit_bytes;
69 self
70 }
71}