Skip to content

Commit 9283a9d

Browse files
committed
fix!: encode::loose_header() now supports large objects even on 32 bit systems.
Previously, larger than 4GB files wouldn't be supported, which causes problems when genrating hashes even when streaming data.
1 parent 260c781 commit 9283a9d

File tree

8 files changed

+31
-27
lines changed

8 files changed

+31
-27
lines changed

gix-object/src/blob.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ impl<'a> crate::WriteTo for BlobRef<'a> {
1212
Kind::Blob
1313
}
1414

15-
fn size(&self) -> usize {
16-
self.data.len()
15+
fn size(&self) -> u64 {
16+
self.data.len() as u64
1717
}
1818
}
1919

@@ -27,7 +27,7 @@ impl crate::WriteTo for Blob {
2727
Kind::Blob
2828
}
2929

30-
fn size(&self) -> usize {
30+
fn size(&self) -> u64 {
3131
self.to_ref().size()
3232
}
3333
}

gix-object/src/commit/write.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ impl crate::WriteTo for Commit {
2727
Kind::Commit
2828
}
2929

30-
fn size(&self) -> usize {
30+
fn size(&self) -> u64 {
3131
let hash_in_hex = self.tree.kind().len_in_hex();
32-
b"tree".len() + 1 /*space*/ + hash_in_hex + 1 /* nl */
32+
(b"tree".len() + 1 /*space*/ + hash_in_hex + 1 /* nl */
3333
+ self.parents.iter().count() * (b"parent".len() + 1 + hash_in_hex + 1)
3434
+ b"author".len() + 1 /* space */ + self.author.size() + 1 /* nl */
3535
+ b"committer".len() + 1 /* space */ + self.committer.size() + 1 /* nl */
@@ -46,7 +46,7 @@ impl crate::WriteTo for Commit {
4646
})
4747
.sum::<usize>()
4848
+ 1 /* nl */
49-
+ self.message.len()
49+
+ self.message.len()) as u64
5050
}
5151
}
5252

@@ -73,9 +73,9 @@ impl<'a> crate::WriteTo for CommitRef<'a> {
7373
Kind::Commit
7474
}
7575

76-
fn size(&self) -> usize {
76+
fn size(&self) -> u64 {
7777
let hash_in_hex = self.tree().kind().len_in_hex();
78-
b"tree".len() + 1 /* space */ + hash_in_hex + 1 /* nl */
78+
(b"tree".len() + 1 /* space */ + hash_in_hex + 1 /* nl */
7979
+ self.parents.iter().count() * (b"parent".len() + 1 /* space */ + hash_in_hex + 1 /* nl */)
8080
+ b"author".len() + 1 /* space */ + self.author.size() + 1 /* nl */
8181
+ b"committer".len() + 1 /* space */ + self.committer.size() + 1 /* nl */
@@ -92,6 +92,6 @@ impl<'a> crate::WriteTo for CommitRef<'a> {
9292
})
9393
.sum::<usize>()
9494
+ 1 /* nl */
95-
+ self.message.len()
95+
+ self.message.len()) as u64
9696
}
9797
}

gix-object/src/encode.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ macro_rules! check {
1919
};
2020
}
2121
/// Generates a loose header buffer
22-
pub fn loose_header(kind: crate::Kind, size: usize) -> smallvec::SmallVec<[u8; 28]> {
22+
pub fn loose_header(kind: crate::Kind, size: u64) -> smallvec::SmallVec<[u8; 28]> {
2323
let mut v = smallvec::SmallVec::new();
2424
check!(v.write_all(kind.as_bytes()));
2525
check!(v.write_all(SPACE));

gix-object/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ pub mod decode {
345345
/// ([`kind`](super::Kind), `size`, `consumed bytes`).
346346
///
347347
/// `size` is the uncompressed size of the payload in bytes.
348-
pub fn loose_header(input: &[u8]) -> Result<(super::Kind, usize, usize), LooseHeaderDecodeError> {
348+
pub fn loose_header(input: &[u8]) -> Result<(super::Kind, u64, usize), LooseHeaderDecodeError> {
349349
use LooseHeaderDecodeError::*;
350350
let kind_end = input.find_byte(0x20).ok_or(InvalidHeader {
351351
message: "Expected '<type> <size>'",
@@ -366,7 +366,7 @@ pub mod decode {
366366

367367
/// A standalone function to compute a hash of kind `hash_kind` for an object of `object_kind` and its `data`.
368368
pub fn compute_hash(hash_kind: gix_hash::Kind, object_kind: Kind, data: &[u8]) -> gix_hash::ObjectId {
369-
let header = encode::loose_header(object_kind, data.len());
369+
let header = encode::loose_header(object_kind, data.len() as u64);
370370

371371
let mut hasher = gix_features::hash::hasher(hash_kind);
372372
hasher.update(&header);

gix-object/src/object/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ mod write {
2424
self.kind()
2525
}
2626

27-
fn size(&self) -> usize {
27+
fn size(&self) -> u64 {
2828
use crate::ObjectRef::*;
2929
match self {
3030
Tree(v) => v.size(),
@@ -52,7 +52,7 @@ mod write {
5252
self.kind()
5353
}
5454

55-
fn size(&self) -> usize {
55+
fn size(&self) -> u64 {
5656
use crate::Object::*;
5757
match self {
5858
Tree(v) => v.size(),
@@ -185,6 +185,8 @@ pub enum LooseDecodeError {
185185
InvalidHeader(#[from] LooseHeaderDecodeError),
186186
#[error(transparent)]
187187
InvalidContent(#[from] DecodeError),
188+
#[error("Object sized {size} does not fit into memory - this can happen on 32 bit systems")]
189+
OutOfMemory { size: u64 },
188190
}
189191

190192
impl<'a> ObjectRef<'a> {
@@ -193,7 +195,7 @@ impl<'a> ObjectRef<'a> {
193195
let (kind, size, offset) = loose_header(data)?;
194196

195197
let body = &data[offset..]
196-
.get(..size)
198+
.get(..size.try_into().map_err(|_| LooseDecodeError::OutOfMemory { size })?)
197199
.ok_or(LooseHeaderDecodeError::InvalidHeader {
198200
message: "object data was shorter than its size declared in the header",
199201
})?;

gix-object/src/tag/write.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,16 @@ impl crate::WriteTo for Tag {
4444
Kind::Tag
4545
}
4646

47-
fn size(&self) -> usize {
48-
b"object".len() + 1 /* space */ + self.target.kind().len_in_hex() + 1 /* nl */
47+
fn size(&self) -> u64 {
48+
(b"object".len() + 1 /* space */ + self.target.kind().len_in_hex() + 1 /* nl */
4949
+ b"type".len() + 1 /* space */ + self.target_kind.as_bytes().len() + 1 /* nl */
5050
+ b"tag".len() + 1 /* space */ + self.name.len() + 1 /* nl */
5151
+ self
5252
.tagger
5353
.as_ref()
5454
.map_or(0, |t| b"tagger".len() + 1 /* space */ + t.size() + 1 /* nl */)
5555
+ 1 /* nl */ + self.message.len()
56-
+ self.pgp_signature.as_ref().map_or(0, |m| 1 /* nl */ + m.len())
56+
+ self.pgp_signature.as_ref().map_or(0, |m| 1 /* nl */ + m.len())) as u64
5757
}
5858
}
5959

@@ -81,16 +81,16 @@ impl<'a> crate::WriteTo for TagRef<'a> {
8181
Kind::Tag
8282
}
8383

84-
fn size(&self) -> usize {
85-
b"object".len() + 1 /* space */ + self.target().kind().len_in_hex() + 1 /* nl */
84+
fn size(&self) -> u64 {
85+
(b"object".len() + 1 /* space */ + self.target().kind().len_in_hex() + 1 /* nl */
8686
+ b"type".len() + 1 /* space */ + self.target_kind.as_bytes().len() + 1 /* nl */
8787
+ b"tag".len() + 1 /* space */ + self.name.len() + 1 /* nl */
8888
+ self
8989
.tagger
9090
.as_ref()
9191
.map_or(0, |t| b"tagger".len() + 1 /* space */ + t.size() + 1 /* nl */)
9292
+ 1 /* nl */ + self.message.len()
93-
+ self.pgp_signature.as_ref().map_or(0, |m| 1 /* nl */ + m.len())
93+
+ self.pgp_signature.as_ref().map_or(0, |m| 1 /* nl */ + m.len())) as u64
9494
}
9595
}
9696

gix-object/src/traits.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub trait WriteTo {
1717
/// the object, as such it's possible for [`size`](Self::size) to
1818
/// return a sensible value but [`write_to`](Self::write_to) to
1919
/// fail because the object was not actually valid in some way.
20-
fn size(&self) -> usize;
20+
fn size(&self) -> u64;
2121

2222
/// Returns a loose object header based on the object's data
2323
fn loose_header(&self) -> smallvec::SmallVec<[u8; 28]> {
@@ -37,7 +37,7 @@ where
3737
<T as WriteTo>::kind(self)
3838
}
3939

40-
fn size(&self) -> usize {
40+
fn size(&self) -> u64 {
4141
<T as WriteTo>::size(self)
4242
}
4343
}

gix-object/src/tree/write.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,12 @@ impl crate::WriteTo for Tree {
5757
Kind::Tree
5858
}
5959

60-
fn size(&self) -> usize {
60+
fn size(&self) -> u64 {
6161
self.entries
6262
.iter()
63-
.map(|Entry { mode, filename, oid }| mode.as_bytes().len() + 1 + filename.len() + 1 + oid.as_bytes().len())
63+
.map(|Entry { mode, filename, oid }| {
64+
(mode.as_bytes().len() + 1 + filename.len() + 1 + oid.as_bytes().len()) as u64
65+
})
6466
.sum()
6567
}
6668
}
@@ -100,11 +102,11 @@ impl<'a> crate::WriteTo for TreeRef<'a> {
100102
Kind::Tree
101103
}
102104

103-
fn size(&self) -> usize {
105+
fn size(&self) -> u64 {
104106
self.entries
105107
.iter()
106108
.map(|EntryRef { mode, filename, oid }| {
107-
mode.as_bytes().len() + 1 + filename.len() + 1 + oid.as_bytes().len()
109+
(mode.as_bytes().len() + 1 + filename.len() + 1 + oid.as_bytes().len()) as u64
108110
})
109111
.sum()
110112
}

0 commit comments

Comments
 (0)