diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:03 +0000 |
commit | 64d98f8ee037282c35007b64c2649055c56af1db (patch) | |
tree | 5492bcf97fce41ee1c0b1cc2add283f3e66cdab0 /vendor/zip/src/crc32.rs | |
parent | Adding debian version 1.67.1+dfsg1-1. (diff) | |
download | rustc-64d98f8ee037282c35007b64c2649055c56af1db.tar.xz rustc-64d98f8ee037282c35007b64c2649055c56af1db.zip |
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/zip/src/crc32.rs')
-rw-r--r-- | vendor/zip/src/crc32.rs | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/vendor/zip/src/crc32.rs b/vendor/zip/src/crc32.rs new file mode 100644 index 000000000..ebace898d --- /dev/null +++ b/vendor/zip/src/crc32.rs @@ -0,0 +1,100 @@ +//! Helper module to compute a CRC32 checksum + +use std::io; +use std::io::prelude::*; + +use crc32fast::Hasher; + +/// Reader that validates the CRC32 when it reaches the EOF. +pub struct Crc32Reader<R> { + inner: R, + hasher: Hasher, + check: u32, + /// Signals if `inner` stores aes encrypted data. + /// AE-2 encrypted data doesn't use crc and sets the value to 0. + ae2_encrypted: bool, +} + +impl<R> Crc32Reader<R> { + /// Get a new Crc32Reader which checks the inner reader against checksum. + /// The check is disabled if `ae2_encrypted == true`. + pub(crate) fn new(inner: R, checksum: u32, ae2_encrypted: bool) -> Crc32Reader<R> { + Crc32Reader { + inner, + hasher: Hasher::new(), + check: checksum, + ae2_encrypted, + } + } + + fn check_matches(&self) -> bool { + self.check == self.hasher.clone().finalize() + } + + pub fn into_inner(self) -> R { + self.inner + } +} + +impl<R: Read> Read for Crc32Reader<R> { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + let invalid_check = !buf.is_empty() && !self.check_matches() && !self.ae2_encrypted; + + let count = match self.inner.read(buf) { + Ok(0) if invalid_check => { + return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum")) + } + Ok(n) => n, + Err(e) => return Err(e), + }; + self.hasher.update(&buf[0..count]); + Ok(count) + } +} + +#[cfg(test)] +mod test { + use super::*; + use std::io::Read; + + #[test] + fn test_empty_reader() { + let data: &[u8] = b""; + let mut buf = [0; 1]; + + let mut reader = Crc32Reader::new(data, 0, false); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + + let mut reader = Crc32Reader::new(data, 1, false); + assert!(reader + .read(&mut buf) + .unwrap_err() + .to_string() + .contains("Invalid checksum")); + } + + #[test] + fn test_byte_by_byte() { + let data: &[u8] = b"1234"; + let mut buf = [0; 1]; + + let mut reader = Crc32Reader::new(data, 0x9be3e0a3, false); + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + // Can keep reading 0 bytes after the end + assert_eq!(reader.read(&mut buf).unwrap(), 0); + } + + #[test] + fn test_zero_read() { + let data: &[u8] = b"1234"; + let mut buf = [0; 5]; + + let mut reader = Crc32Reader::new(data, 0x9be3e0a3, false); + assert_eq!(reader.read(&mut buf[..0]).unwrap(), 0); + assert_eq!(reader.read(&mut buf).unwrap(), 4); + } +} |