Unified · Split
| @@ -104,11 +104,11 @@ mod header { · 103 unmodified lines | ||
| 104 | 104 | } |
| 105 | 105 | } |
| 106 | 106 | |
| 107 | − impl From<(usize, gix_object::Kind)> for Header { | |
| 108 | − fn from((object_size, kind): (usize, gix_object::Kind)) -> Self { | |
| 107 | + impl From<(u64, gix_object::Kind)> for Header { | |
| 108 | + fn from((object_size, kind): (u64, gix_object::Kind)) -> Self { | |
| 109 | 109 | Header::Loose { |
| 110 | 110 | kind, |
| 111 | − size: object_size as u64, | |
| 111 | + size: object_size, | |
| 112 | 112 | } |
| 113 | 113 | } |
| 114 | 114 | } |
| @@ -1,6 +1,5 @@ | ||
| 1 | 1 | use std::{ |
| 2 | 2 | cell::RefCell, |
| 3 | − convert::TryInto, | |
| 4 | 3 | io::{self, Write}, |
| 5 | 4 | }; |
| 6 | 5 | |
| @@ -24,11 +23,10 @@ impl crate::traits::Write for Sink { · 17 unmodified lines | ||
| 24 | 23 | fn write_stream( |
| 25 | 24 | &self, |
| 26 | 25 | kind: gix_object::Kind, |
| 27 | − size: u64, | |
| 26 | + mut size: u64, | |
| 28 | 27 | from: &mut dyn io::Read, |
| 29 | 28 | ) -> Result<gix_hash::ObjectId, crate::write::Error> { |
| 30 | − let mut size = size.try_into().expect("object size to fit into usize"); | |
| 31 | − let mut buf = [0u8; 8096]; | |
| 29 | + let mut buf = [0u8; u16::MAX as usize]; | |
| 32 | 30 | let header = gix_object::encode::loose_header(kind, size); |
| 33 | 31 | |
| 34 | 32 | let possibly_compress = |buf: &[u8]| -> io::Result<()> { |
| @@ -43,11 +41,11 @@ impl crate::traits::Write for Sink { · 8 unmodified lines | ||
| 43 | 41 | possibly_compress(&header).map_err(Box::new)?; |
| 44 | 42 | |
| 45 | 43 | while size != 0 { |
| 46 | − let bytes = size.min(buf.len()); | |
| 44 | + let bytes = (size as usize).min(buf.len()); | |
| 47 | 45 | from.read_exact(&mut buf[..bytes]).map_err(Box::new)?; |
| 48 | 46 | hasher.update(&buf[..bytes]); |
| 49 | 47 | possibly_compress(&buf[..bytes]).map_err(Box::new)?; |
| 50 | − size -= bytes; | |
| 48 | + size -= bytes as u64; | |
| 51 | 49 | } |
| 52 | 50 | if let Some(compressor) = self.compressor.as_ref() { |
| 53 | 51 | let mut c = compressor.borrow_mut(); |
| @@ -14,13 +14,11 @@ pub enum Error { · 13 unmodified lines | ||
| 14 | 14 | path: PathBuf, |
| 15 | 15 | }, |
| 16 | 16 | #[error("file at '{path}' showed invalid size of inflated data, expected {expected}, got {actual}")] |
| 17 | − SizeMismatch { | |
| 18 | − actual: usize, | |
| 19 | − expected: usize, | |
| 20 | − path: PathBuf, | |
| 21 | − }, | |
| 17 | + SizeMismatch { actual: u64, expected: u64, path: PathBuf }, | |
| 22 | 18 | #[error(transparent)] |
| 23 | 19 | Decode(#[from] gix_object::decode::LooseHeaderDecodeError), |
| 20 | + #[error("Cannot store {size} in memory as it's not representable")] | |
| 21 | + OutOfMemory { size: u64 }, | |
| 24 | 22 | #[error("Could not {action} data at '{path}'")] |
| 25 | 23 | Io { |
| 26 | 24 | source: std::io::Error, |
| @@ -137,7 +135,7 @@ impl Store { · 110 unmodified lines | ||
| 137 | 135 | |
| 138 | 136 | /// Return only the decompressed size of the object and its kind without fully reading it into memory as tuple of `(size, kind)`. |
| 139 | 137 | /// Returns `None` if `id` does not exist in the database. |
| 140 | − pub fn try_header(&self, id: &gix_hash::oid) -> Result<Option<(usize, gix_object::Kind)>, Error> { | |
| 138 | + pub fn try_header(&self, id: &gix_hash::oid) -> Result<Option<(u64, gix_object::Kind)>, Error> { | |
| 141 | 139 | const BUF_SIZE: usize = 256; |
| 142 | 140 | let mut buf = [0_u8; BUF_SIZE]; |
| 143 | 141 | let path = hash_path(id, self.path.clone()); |
| @@ -224,16 +222,17 @@ impl Store { · 80 unmodified lines | ||
| 224 | 222 | let decompressed_body_bytes_sans_header = |
| 225 | 223 | decompressed_start + header_size..decompressed_start + consumed_out; |
| 226 | 224 | |
| 227 | − if consumed_out != size + header_size { | |
| 225 | + if consumed_out as u64 != size + header_size as u64 { | |
| 228 | 226 | return Err(Error::SizeMismatch { |
| 229 | − expected: size + header_size, | |
| 230 | − actual: consumed_out, | |
| 227 | + expected: size + header_size as u64, | |
| 228 | + actual: consumed_out as u64, | |
| 231 | 229 | path, |
| 232 | 230 | }); |
| 233 | 231 | } |
| 234 | 232 | buf.copy_within(decompressed_body_bytes_sans_header, 0); |
| 235 | 233 | } else { |
| 236 | − buf.resize(bytes_read + size + header_size, 0); | |
| 234 | + let new_len = bytes_read as u64 + size + header_size as u64; | |
| 235 | + buf.resize(new_len.try_into().map_err(|_| Error::OutOfMemory { size: new_len })?, 0); | |
| 237 | 236 | { |
| 238 | 237 | let (input, output) = buf.split_at_mut(bytes_read); |
| 239 | 238 | let num_decompressed_bytes = zlib::stream::inflate::read( |
| @@ -246,17 +245,21 @@ impl Store { · 6 unmodified lines | ||
| 246 | 245 | action: "deflate", |
| 247 | 246 | path: path.to_owned(), |
| 248 | 247 | })?; |
| 249 | − if num_decompressed_bytes + consumed_out != size + header_size { | |
| 248 | + if num_decompressed_bytes as u64 + consumed_out as u64 != size + header_size as u64 { | |
| 250 | 249 | return Err(Error::SizeMismatch { |
| 251 | − expected: size + header_size, | |
| 252 | − actual: num_decompressed_bytes + consumed_out, | |
| 250 | + expected: size + header_size as u64, | |
| 251 | + actual: num_decompressed_bytes as u64 + consumed_out as u64, | |
| 253 | 252 | path, |
| 254 | 253 | }); |
| 255 | 254 | } |
| 256 | 255 | }; |
| 257 | 256 | buf.copy_within(decompressed_start + header_size.., 0); |
| 258 | 257 | } |
| 259 | − buf.resize(size, 0); | |
| 258 | + buf.resize( | |
| 259 | + size.try_into() | |
| 260 | + .expect("BUG: here the size is already confirmed to fit into memory"), | |
| 261 | + 0, | |
| 262 | + ); | |
| 260 | 263 | Ok(gix_object::Data { kind, data: buf }) |
| 261 | 264 | } |
| 262 | 265 | } |
| @@ -1,4 +1,4 @@ | ||
| 1 | −use std::{convert::TryInto, fs, io, io::Write, path::PathBuf}; | |
| 1 | +use std::{fs, io, io::Write, path::PathBuf}; | |
| 2 | 2 | |
| 3 | 3 | use gix_features::{hash, zlib::stream::deflate}; |
| 4 | 4 | use gix_object::WriteTo; |
| @@ -48,7 +48,7 @@ impl crate::traits::Write for Store { · 43 unmodified lines | ||
| 48 | 48 | /// This will cost at least 4 IO operations. |
| 49 | 49 | fn write_buf(&self, kind: gix_object::Kind, from: &[u8]) -> Result<gix_hash::ObjectId, crate::write::Error> { |
| 50 | 50 | let mut to = self.dest().map_err(Box::new)?; |
| 51 | − to.write_all(&gix_object::encode::loose_header(kind, from.len())) | |
| 51 | + to.write_all(&gix_object::encode::loose_header(kind, from.len() as u64)) | |
| 52 | 52 | .map_err(|err| Error::Io { |
| 53 | 53 | source: err, |
| 54 | 54 | message: "write header to tempfile in", |
| @@ -74,15 +74,12 @@ impl crate::traits::Write for Store { · 19 unmodified lines | ||
| 74 | 74 | mut from: &mut dyn io::Read, |
| 75 | 75 | ) -> Result<gix_hash::ObjectId, crate::write::Error> { |
| 76 | 76 | let mut to = self.dest().map_err(Box::new)?; |
| 77 | − to.write_all(&gix_object::encode::loose_header( | |
| 78 | − kind, | |
| 79 | − size.try_into().expect("object size to fit into usize"), | |
| 80 | − )) | |
| 81 | − .map_err(|err| Error::Io { | |
| 82 | − source: err, | |
| 83 | − message: "write header to tempfile in", | |
| 84 | − path: self.path.to_owned(), | |
| 85 | − })?; | |
| 77 | + to.write_all(&gix_object::encode::loose_header(kind, size)) | |
| 78 | + .map_err(|err| Error::Io { | |
| 79 | + source: err, | |
| 80 | + message: "write header to tempfile in", | |
| 81 | + path: self.path.to_owned(), | |
| 82 | + })?; | |
| 86 | 83 | |
| 87 | 84 | io::copy(&mut from, &mut to) |
| 88 | 85 | .map_err(|err| Error::Io { |
| @@ -420,7 +420,7 @@ cjHJZXWmV4CcRfmLsXzU8s2cR9A0DBvOxhPD1TlKC2JhBFXigjuL9U4Rbq9tdegB · 419 unmodified lines | ||
| 420 | 420 | let id = id?; |
| 421 | 421 | let expected = db.try_find(&id, &mut buf)?.expect("exists"); |
| 422 | 422 | let (size, kind) = db.try_header(&id)?.expect("header exists"); |
| 423 | − assert_eq!(size, expected.data.len()); | |
| 423 | + assert_eq!(size, expected.data.len() as u64); | |
| 424 | 424 | assert_eq!(kind, expected.kind); |
| 425 | 425 | } |
| 426 | 426 | Ok(()) |