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