Skip to content

Commit

Permalink
Merge pull request #316 from NobodyXu/streaming
Browse files Browse the repository at this point in the history
Implement a high-level, easy-to-use streaming decoder that recover all information from a zip
  • Loading branch information
Plecra authored Feb 1, 2023
2 parents 0a09253 + c4c6ec9 commit e32db51
Show file tree
Hide file tree
Showing 7 changed files with 457 additions and 49 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ keywords = ["zip", "archive"]
description = """
Library to support the reading and writing of zip files.
"""
edition = "2018"
edition = "2021"

[dependencies]
aes = { version = "0.7.5", optional = true }
Expand Down
11 changes: 11 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,14 @@ mod spec;
mod types;
pub mod write;
mod zipcrypto;

/// Unstable APIs
///
/// All APIs accessible by importing this module are unstable; They may be changed in patch releases.
/// You MUST you an exact version specifier in `Cargo.toml`, to indicate the version of this API you're using:
///
/// ```toml
/// [dependencies]
/// zip = "=0.6.4"
/// ```
pub mod unstable;
64 changes: 19 additions & 45 deletions src/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use byteorder::{LittleEndian, ReadBytesExt};
use std::borrow::Cow;
use std::collections::HashMap;
use std::io::{self, prelude::*};
use std::path::{Component, Path};
use std::path::Path;
use std::sync::Arc;

#[cfg(any(
Expand All @@ -29,10 +29,8 @@ use bzip2::read::BzDecoder;
#[cfg(feature = "zstd")]
use zstd::stream::read::Decoder as ZstdDecoder;

mod ffi {
pub const S_IFDIR: u32 = 0o0040000;
pub const S_IFREG: u32 = 0o0100000;
}
/// Provides high level API for reading from a stream.
pub(crate) mod stream;

// Put the struct declaration in a private module to convince rustdoc to display ZipArchive nicely
pub(crate) mod zip_archive {
Expand Down Expand Up @@ -650,12 +648,22 @@ pub(crate) fn central_header_to_zip_file<R: Read + io::Seek>(
archive_offset: u64,
) -> ZipResult<ZipFileData> {
let central_header_start = reader.stream_position()?;

// Parse central header
let signature = reader.read_u32::<LittleEndian>()?;
if signature != spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE {
return Err(ZipError::InvalidArchive("Invalid Central Directory header"));
Err(ZipError::InvalidArchive("Invalid Central Directory header"))
} else {
central_header_to_zip_file_inner(reader, archive_offset, central_header_start)
}
}

/// Parse a central directory entry to collect the information for the file.
fn central_header_to_zip_file_inner<R: Read>(
reader: &mut R,
archive_offset: u64,
central_header_start: u64,
) -> ZipResult<ZipFileData> {
let version_made_by = reader.read_u16::<LittleEndian>()?;
let _version_to_extract = reader.read_u16::<LittleEndian>()?;
let flags = reader.read_u16::<LittleEndian>()?;
Expand Down Expand Up @@ -896,20 +904,7 @@ impl<'a> ZipFile<'a> {
/// to path-based exploits. It is recommended over
/// [`ZipFile::mangled_name`].
pub fn enclosed_name(&self) -> Option<&Path> {
if self.data.file_name.contains('\0') {
return None;
}
let path = Path::new(&self.data.file_name);
let mut depth = 0usize;
for component in path.components() {
match component {
Component::Prefix(_) | Component::RootDir => return None,
Component::ParentDir => depth = depth.checked_sub(1)?,
Component::Normal(_) => depth += 1,
Component::CurDir => (),
}
}
Some(path)
self.data.enclosed_name()
}

/// Get the comment of the file
Expand Down Expand Up @@ -952,27 +947,7 @@ impl<'a> ZipFile<'a> {

/// Get unix mode for the file
pub fn unix_mode(&self) -> Option<u32> {
if self.data.external_attributes == 0 {
return None;
}

match self.data.system {
System::Unix => Some(self.data.external_attributes >> 16),
System::Dos => {
// Interpret MS-DOS directory bit
let mut mode = if 0x10 == (self.data.external_attributes & 0x10) {
ffi::S_IFDIR | 0o0775
} else {
ffi::S_IFREG | 0o0664
};
if 0x01 == (self.data.external_attributes & 0x01) {
// Read-only bit; strip write permissions
mode &= 0o0555;
}
Some(mode)
}
_ => None,
}
self.data.unix_mode()
}

/// Get the CRC32 hash of the original file
Expand Down Expand Up @@ -1029,10 +1004,9 @@ impl<'a> Drop for ZipFile<'a> {
match reader.read(&mut buffer) {
Ok(0) => break,
Ok(_) => (),
Err(e) => panic!(
"Could not consume all of the output of the current ZipFile: {:?}",
e
),
Err(e) => {
panic!("Could not consume all of the output of the current ZipFile: {e:?}")
}
}
}
}
Expand Down
Loading

0 comments on commit e32db51

Please sign in to comment.