1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
# zip [](https://crates.io/crates/zip)  [](https://docs.rs/zip) [](https://github.com/zip-rs/zip2/actions?query=branch%3Amaster+workflow%3ACI) [](https://www.bestpractices.dev/projects/11847)
A zip library for rust which supports reading and writing of simple ZIP files. Currently hosted at
<https://github.com/zip-rs/zip2>.
Supported compression formats:
- Compress and decompress:
- stored (i.e. none)
- deflate
- bzip2
- zstd
- xz
- ppmd
- Decompress only:
- deflate64
- lzma
- implode
- reduce
- shrink
Currently unsupported zip extensions:
- Multi-disk
## Features
The features available are:
- `aes-crypto`: Enables decryption of files which were encrypted with AES. Supports AE-1 and AE-2 methods.
- `deflate`: Enables compressing and decompressing an unspecified implementation (that may change in future versions) of
the deflate compression algorithm, which is the default for zip files. Supports compression quality 1..=264.
- `deflate-flate2`: Combine this with any `flate2` feature flag that enables a back-end, to support deflate compression
at quality 1..=9.
- `deflate-zopfli`: Enables deflating files with the `zopfli` library (used when compression quality is 10..=264). This
is the most effective `deflate` implementation available, but also among the slowest. If `flate2` isn't also enabled,
only compression will be supported and not decompression.
- `deflate64`: Enables the deflate64 compression algorithm. Only decompression is supported.
- `lzma`: Enables the LZMA compression algorithm. Only decompression is supported.
- `bzip2`: Enables the BZip2 compression algorithm.
- `ppmd`: Enables the PPMd compression algorithm.
- `time`: Enables features using the [time](https://github.com/time-rs/time) crate.
- `chrono`: Enables converting last-modified `zip::DateTime` to and from `chrono::NaiveDateTime`.
- `jiff-02`: Enables converting last-modified `zip::DateTime` to and from `jiff::civil::DateTime`.
- `nt-time`: Enables returning timestamps stored in the NTFS extra field as `nt_time::FileTime`.
- `xz`: Enables the XZ compression algorithm.
- `zstd`: Enables the Zstandard compression algorithm.
By default `aes-crypto`, `bzip2`, `deflate`, `deflate64`, `lzma`, `ppmd`, `time`, `xz` and `zstd` are enabled.
## MSRV
Our current Minimum Supported Rust Version is **1.88**. When adding features,
we will follow these guidelines:
- We will always support a minor Rust version that has been stable for at least 6 months.
- Any change to the MSRV will be accompanied with a **minor** version bump.
## Examples
See the [examples directory](examples) for:
- How to [write a file to a zip](./examples/write_sample.rs).
- How to [write a directory of files to a zip](./examples/write_dir.rs) (using [walkdir](https://github.com/BurntSushi/walkdir)).
- How to [extract a zip file](./examples/extract.rs).
- How to [extract a single file from a zip](./examples/extract_lorem.rs).
- How to [read a zip from the standard input](./examples/stdin_info.rs).
- How to [append a directory to an existing archive](./examples/append.rs)
## Fuzzing
Fuzzing support is through [`cargo afl`](https://rust-fuzz.github.io/book/afl/tutorial.html). To install `cargo afl`:
```sh
cargo install cargo-afl
```
To start fuzzing zip extraction:
```sh
mkdir -vp fuzz-read-out
cargo afl build --manifest-path=fuzz/Cargo.toml --all-features -p fuzz_read
# Curated input corpus:
cargo afl fuzz -i fuzz/read/in -o fuzz-read-out fuzz/target/debug/fuzz_read
# Test data files:
cargo afl fuzz -i tests/data -e zip -o fuzz-read-out fuzz/target/debug/fuzz_read
```
To start fuzzing zip creation:
```sh
mkdir -vp fuzz-write-out
cargo afl build --manifest-path=fuzz/Cargo.toml --all-features -p fuzz_write
# Curated input corpus and dictionary schema:
cargo afl fuzz -x fuzz/write/fuzz.dict -i fuzz/write/in -o fuzz-write-out fuzz/target/debug/fuzz_write
```
## Fuzzing stdio
The read and write fuzzers can also receive input over stdin for one-off validation. Note here that the fuzzers can be configured to build in support for DEFLATE, or not:
```sh
# Success, no output:
cargo run --manifest-path=fuzz/Cargo.toml --quiet --all-features -p fuzz_read <tests/data/deflate64.zip
# Error, without deflate64 support:
cargo run --manifest-path=fuzz/Cargo.toml --quiet -p fuzz_read <tests/data/deflate64.zip
thread 'main' (537304) panicked at fuzz_read/src/main.rs:40:36:
called `Result::unwrap()` on an `Err` value: UnsupportedArchive("Compression method not supported")
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```
The zip creation fuzzer will try to print out a description of the kind of input it translated the input bytes into:
```sh
# This is an empty input case:
<fuzz/write/in/id-000000,time-0,execs-0,orig-0011743621118ab6c5278ffbb8fd14bddd8369ee.min \
cargo run --manifest-path=fuzz/Cargo.toml --quiet --all-features -p fuzz_write
# This input was translated into one or more test cases:
<fuzz/write/in/id-000000,time-0,execs-0,orig-0011743621118ab6c5278ffbb8fd14bddd8369ee.min \
cargo run --manifest-path=fuzz/Cargo.toml --quiet -p fuzz_write
writer.start_file_from_path("", FileOptions { compression_method: Stored, compression_level: None, last_modified_time: DateTime::from_date_and_time(2048, 1, 1, 0, 0, 0)?, permissions: None, large_file: false, encrypt_with: None, extended_options: ExtendedFileOptions {extra_data: vec![].into(), central_extra_data: vec![].into()}, alignment: 0 })?;
writer.write_all(&[])?;
writer
let _ = writer.finish_into_readable()?;
```
The zip creation fuzzer uses [`arbitrary::Unstructured`](https://docs.rs/arbitrary/latest/arbitrary/struct.Unstructured.html) to convert bytes over stdin to random inputs, so it can be triggered with other sources of random input:
```sh
# Usually, the random input is translated into zero test cases:
head -c50 /dev/random | cargo run --manifest-path=fuzz/Cargo.toml --quiet --all-features -p fuzz_write
# Sometimes, one or more test cases are generated and successfully evaluated:
head -c50 /dev/random | cargo run --manifest-path=fuzz/Cargo.toml --quiet --all-features -p fuzz_write
writer.set_raw_comment([20, 202])?;
let mut writer = ZipWriter::new_append(writer.finish()?)?;
let sub_writer = {
let mut initial_junk = Cursor::new(vec![106]);
initial_junk.seek(SeekFrom::End(0))?;
let mut writer = ZipWriter::new(initial_junk);
writer
};
writer.merge_archive(sub_writer.finish_into_readable()?)?;
let mut writer = ZipWriter::new_append(writer.finish()?)?;
```
|