Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Improve several Read methods on ZipFile #45

Merged
merged 1 commit into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 41 additions & 10 deletions src/crc32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub struct Crc32Reader<R> {
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,
enabled: bool,
}

impl<R> Crc32Reader<R> {
Expand All @@ -23,7 +23,7 @@ impl<R> Crc32Reader<R> {
inner,
hasher: Hasher::new(),
check: checksum,
ae2_encrypted,
enabled: !ae2_encrypted,
}
}

Expand All @@ -36,20 +36,51 @@ impl<R> Crc32Reader<R> {
}
}

#[cold]
fn invalid_checksum() -> io::Error {
io::Error::new(io::ErrorKind::InvalidData, "Invalid checksum")
}

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 = self.inner.read(buf)?;

let count = match self.inner.read(buf) {
Ok(0) if invalid_check => {
return Err(io::Error::new(io::ErrorKind::Other, "Invalid checksum"))
if self.enabled {
if count == 0 && !buf.is_empty() && !self.check_matches() {
return Err(invalid_checksum());
}
Ok(n) => n,
Err(e) => return Err(e),
};
self.hasher.update(&buf[0..count]);
self.hasher.update(&buf[..count]);
}
Ok(count)
}

fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
let start = buf.len();
let n = self.inner.read_to_end(buf)?;

if self.enabled {
self.hasher.update(&buf[start..]);
if !self.check_matches() {
return Err(invalid_checksum());
}
}

Ok(n)
}

fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
let start = buf.len();
let n = self.inner.read_to_string(buf)?;

if self.enabled {
self.hasher.update(&buf.as_bytes()[start..]);
if !self.check_matches() {
return Err(invalid_checksum());
}
}

Ok(n)
}
}

#[cfg(test)]
Expand Down
90 changes: 90 additions & 0 deletions src/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,24 @@
CryptoReader::Aes { reader: r, .. } => r.read(buf),
}
}

fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
match self {
CryptoReader::Plaintext(r) => r.read_to_end(buf),
CryptoReader::ZipCrypto(r) => r.read_to_end(buf),
#[cfg(feature = "aes-crypto")]
CryptoReader::Aes { reader: r, .. } => r.read_to_end(buf),
}
}

fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
match self {
CryptoReader::Plaintext(r) => r.read_to_string(buf),
CryptoReader::ZipCrypto(r) => r.read_to_string(buf),
#[cfg(feature = "aes-crypto")]
CryptoReader::Aes { reader: r, .. } => r.read_to_string(buf),
}
}
}

impl<'a> CryptoReader<'a> {
Expand Down Expand Up @@ -219,6 +237,66 @@
ZipFileReader::Xz(r) => r.read(buf),
}
}

fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
match self {
ZipFileReader::NoReader => panic!("ZipFileReader was in an invalid state"),
ZipFileReader::Raw(r) => r.read_exact(buf),
ZipFileReader::Stored(r) => r.read_exact(buf),
#[cfg(feature = "_deflate-any")]
ZipFileReader::Deflated(r) => r.read_exact(buf),
#[cfg(feature = "deflate64")]
ZipFileReader::Deflate64(r) => r.read_exact(buf),
#[cfg(feature = "bzip2")]
ZipFileReader::Bzip2(r) => r.read_exact(buf),
#[cfg(feature = "zstd")]
ZipFileReader::Zstd(r) => r.read_exact(buf),
#[cfg(feature = "lzma")]
ZipFileReader::Lzma(r) => r.read_exact(buf),
#[cfg(feature = "xz")]
ZipFileReader::Xz(r) => r.read_exact(buf),
}
}

fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
match self {
ZipFileReader::NoReader => panic!("ZipFileReader was in an invalid state"),
ZipFileReader::Raw(r) => r.read_to_end(buf),
ZipFileReader::Stored(r) => r.read_to_end(buf),
#[cfg(feature = "_deflate-any")]
ZipFileReader::Deflated(r) => r.read_to_end(buf),
#[cfg(feature = "deflate64")]
ZipFileReader::Deflate64(r) => r.read_to_end(buf),
#[cfg(feature = "bzip2")]
ZipFileReader::Bzip2(r) => r.read_to_end(buf),
#[cfg(feature = "zstd")]
ZipFileReader::Zstd(r) => r.read_to_end(buf),
#[cfg(feature = "lzma")]
ZipFileReader::Lzma(r) => r.read_to_end(buf),
#[cfg(feature = "xz")]
ZipFileReader::Xz(r) => r.read_to_end(buf),
}
}

fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
match self {
ZipFileReader::NoReader => panic!("ZipFileReader was in an invalid state"),
ZipFileReader::Raw(r) => r.read_to_string(buf),
ZipFileReader::Stored(r) => r.read_to_string(buf),
#[cfg(feature = "_deflate-any")]
ZipFileReader::Deflated(r) => r.read_to_string(buf),
#[cfg(feature = "deflate64")]
ZipFileReader::Deflate64(r) => r.read_to_string(buf),
#[cfg(feature = "bzip2")]
ZipFileReader::Bzip2(r) => r.read_to_string(buf),
#[cfg(feature = "zstd")]
ZipFileReader::Zstd(r) => r.read_to_string(buf),
#[cfg(feature = "lzma")]
ZipFileReader::Lzma(r) => r.read_to_string(buf),
#[cfg(feature = "xz")]
ZipFileReader::Xz(r) => r.read_to_string(buf),
}
}
}

impl<'a> ZipFileReader<'a> {
Expand Down Expand Up @@ -1526,7 +1604,7 @@
/// `foo/../bar` as `foo/bar` (instead of `bar`). Because of this,
/// [`ZipFile::enclosed_name`] is the better option in most scenarios.
///
/// [`ParentDir`]: `Component::ParentDir`

Check warning on line 1607 in src/read.rs

View workflow job for this annotation

GitHub Actions / style_and_docs (--no-default-features)

unresolved link to `Component::ParentDir`

Check warning on line 1607 in src/read.rs

View workflow job for this annotation

GitHub Actions / style_and_docs (--all-features)

unresolved link to `Component::ParentDir`

Check warning on line 1607 in src/read.rs

View workflow job for this annotation

GitHub Actions / style_and_docs

unresolved link to `Component::ParentDir`
pub fn mangled_name(&self) -> PathBuf {
self.data.file_name_sanitized()
}
Expand Down Expand Up @@ -1624,6 +1702,18 @@
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.get_reader()?.read(buf)
}

fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
self.get_reader()?.read_exact(buf)
}

fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
self.get_reader()?.read_to_end(buf)
}

fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
self.get_reader()?.read_to_string(buf)
}
}

impl<'a> Drop for ZipFile<'a> {
Expand Down
Loading