diff options
author | Jeff Vander Stoep <jeffv@google.com> | 2022-12-19 12:28:35 +0100 |
---|---|---|
committer | Jeff Vander Stoep <jeffv@google.com> | 2022-12-19 12:29:02 +0100 |
commit | e1b598396a56f229babc3245b67fbae386726d42 (patch) | |
tree | e6b7e539d06b28d1944fa5b03ed723b4c68941b0 | |
parent | b40b0b329eef88b8b32b667b0009bd309d1455bf (diff) | |
download | zip-e1b598396a56f229babc3245b67fbae386726d42.tar.gz |
Upgrade zip to 0.6.3main-16k-with-phones
This project was upgraded with external_updater.
Usage: tools/external_updater/updater.sh update rust/crates/zip
For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
Test: TreeHugger
Change-Id: Iae74ec57218a02d84073321972326ce530365dbc
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | .github/workflows/ci.yaml | 18 | ||||
-rw-r--r-- | Android.bp | 2 | ||||
-rw-r--r-- | Cargo.lock.saved | 457 | ||||
-rw-r--r-- | Cargo.toml | 51 | ||||
-rw-r--r-- | Cargo.toml.orig | 12 | ||||
-rw-r--r-- | METADATA | 12 | ||||
-rw-r--r-- | README.md | 29 | ||||
-rw-r--r-- | benches/read_metadata.rs | 41 | ||||
-rw-r--r-- | src/read.rs | 48 | ||||
-rw-r--r-- | src/write.rs | 124 | ||||
-rw-r--r-- | tests/data/invalid_cde_number_of_files_allocation_greater_offset.zip | bin | 0 -> 124 bytes | |||
-rw-r--r-- | tests/data/invalid_cde_number_of_files_allocation_smaller_offset.zip | bin | 0 -> 212 bytes |
13 files changed, 760 insertions, 36 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index b50dc02..1e6556d 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "4f7609cec700765525a537747c8f340dd1090aa0" + "sha1": "1774bb872b6de398a75f3855457bb78fbfab4b5d" }, "path_in_vcs": "" }
\ No newline at end of file diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6f0e4b9..35d4a6e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -16,7 +16,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macOS-latest, windows-latest] - rust: [stable, 1.54.0] + rust: [stable, 1.59.0] steps: - uses: actions/checkout@master @@ -74,3 +74,19 @@ jobs: - name: Docs run: cargo doc + + fuzz: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + override: true + + - run: cargo install cargo-fuzz + - name: compile fuzz + run: | + cargo fuzz build fuzz_read @@ -23,7 +23,7 @@ rust_library { host_supported: true, crate_name: "zip", cargo_env_compat: true, - cargo_pkg_version: "0.6.2", + cargo_pkg_version: "0.6.3", srcs: ["src/lib.rs"], edition: "2018", features: [ diff --git a/Cargo.lock.saved b/Cargo.lock.saved new file mode 100644 index 0000000..1da5fdf --- /dev/null +++ b/Cargo.lock.saved @@ -0,0 +1,457 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "base64ct" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" + +[[package]] +name = "bencher" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5" + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bzip2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6afcd980b5f3a45017c57e57a2fcccbb351cc43a356ce117ef760ef8052b89b0" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "crypto-common" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + +[[package]] +name = "flate2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +dependencies = [ + "crc32fast", + "libz-sys", + "miniz_oxide", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + +[[package]] +name = "jobserver" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" + +[[package]] +name = "libz-sys" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "miniz_oxide" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" +dependencies = [ + "adler", +] + +[[package]] +name = "num_threads" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aba1801fb138d8e85e11d0fc70baf4fe1cdfffda7c6cd34a854905df588e5ed0" +dependencies = [ + "libc", +] + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "sha1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "time" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2702e08a7a860f005826c6815dcac101b19b5eb330c27fe4a5928fec1d20ddd" +dependencies = [ + "itoa", + "libc", + "num_threads", + "time-macros", +] + +[[package]] +name = "time-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792" + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "zip" +version = "0.6.3" +dependencies = [ + "aes", + "bencher", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "getrandom", + "hmac", + "pbkdf2", + "sha1", + "time", + "walkdir", + "zstd", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.1+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fd07cbbc53846d9145dbffdf6dd09a7a0aa52be46741825f5c97bdd4f73f12b" +dependencies = [ + "cc", + "libc", +] @@ -12,16 +12,30 @@ [package] edition = "2018" name = "zip" -version = "0.6.2" -authors = ["Mathijs van de Nes <git@mathijs.vd-nes.nl>", "Marli Frost <marli@frost.red>", "Ryan Levick <ryan.levick@gmail.com>"] -description = "Library to support the reading and writing of zip files.\n" -keywords = ["zip", "archive"] +version = "0.6.3" +authors = [ + "Mathijs van de Nes <git@mathijs.vd-nes.nl>", + "Marli Frost <marli@frost.red>", + "Ryan Levick <ryan.levick@gmail.com>", +] +description = """ +Library to support the reading and writing of zip files. +""" +keywords = [ + "zip", + "archive", +] license = "MIT" repository = "https://github.com/zip-rs/zip.git" [[bench]] name = "read_entry" harness = false + +[[bench]] +name = "read_metadata" +harness = false + [dependencies.aes] version = "0.7.5" optional = true @@ -41,7 +55,7 @@ optional = true version = "1.3.2" [dependencies.flate2] -version = "1.0.22" +version = "1.0.23" optional = true default-features = false @@ -51,7 +65,7 @@ features = ["reset"] optional = true [dependencies.pbkdf2] -version = "0.10.1" +version = "0.11.0" optional = true [dependencies.sha1] @@ -60,12 +74,16 @@ optional = true [dependencies.time] version = "0.3.7" -features = ["formatting", "macros"] +features = [ + "formatting", + "macros", +] optional = true [dependencies.zstd] -version = "0.10.0" +version = "0.11.0" optional = true + [dev-dependencies.bencher] version = "0.1.5" @@ -76,11 +94,24 @@ version = "0.2.5" version = "2.3.2" [features] -aes-crypto = ["aes", "constant_time_eq", "hmac", "pbkdf2", "sha1"] -default = ["aes-crypto", "bzip2", "deflate", "time", "zstd"] +aes-crypto = [ + "aes", + "constant_time_eq", + "hmac", + "pbkdf2", + "sha1", +] +default = [ + "aes-crypto", + "bzip2", + "deflate", + "time", + "zstd", +] deflate = ["flate2/rust_backend"] deflate-miniz = ["flate2/default"] deflate-zlib = ["flate2/zlib"] unreserved = [] + [target."cfg(any(all(target_arch = \"arm\", target_pointer_width = \"32\"), target_arch = \"mips\", target_arch = \"powerpc\"))".dependencies.crossbeam-utils] version = "0.8.8" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index cc87821..a6996fc 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "zip" -version = "0.6.2" +version = "0.6.3" authors = ["Mathijs van de Nes <git@mathijs.vd-nes.nl>", "Marli Frost <marli@frost.red>", "Ryan Levick <ryan.levick@gmail.com>"] license = "MIT" repository = "https://github.com/zip-rs/zip.git" @@ -16,12 +16,12 @@ byteorder = "1.4.3" bzip2 = { version = "0.4.3", optional = true } constant_time_eq = { version = "0.1.5", optional = true } crc32fast = "1.3.2" -flate2 = { version = "1.0.22", default-features = false, optional = true } +flate2 = { version = "1.0.23", default-features = false, optional = true } hmac = { version = "0.12.1", optional = true, features = ["reset"] } -pbkdf2 = {version = "0.10.1", optional = true } +pbkdf2 = {version = "0.11.0", optional = true } sha1 = {version = "0.10.1", optional = true } time = { version = "0.3.7", features = ["formatting", "macros" ], optional = true } -zstd = { version = "0.10.0", optional = true } +zstd = { version = "0.11.0", optional = true } [target.'cfg(any(all(target_arch = "arm", target_pointer_width = "32"), target_arch = "mips", target_arch = "powerpc"))'.dependencies] crossbeam-utils = "0.8.8" @@ -42,3 +42,7 @@ default = ["aes-crypto", "bzip2", "deflate", "time", "zstd"] [[bench]] name = "read_entry" harness = false + +[[bench]] +name = "read_metadata" +harness = false @@ -1,3 +1,7 @@ +# This project was upgraded with external_updater. +# Usage: tools/external_updater/updater.sh update rust/crates/zip +# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md + name: "zip" description: "Library to support the reading and writing of zip files." third_party { @@ -7,13 +11,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/zip/zip-0.6.2.crate" + value: "https://static.crates.io/crates/zip/zip-0.6.3.crate" } - version: "0.6.2" + version: "0.6.3" license_type: NOTICE last_upgrade_date { year: 2022 - month: 4 - day: 13 + month: 12 + day: 19 } } @@ -5,7 +5,7 @@ zip-rs [![Crates.io version](https://img.shields.io/crates/v/zip.svg)](https://crates.io/crates/zip) [![Discord](https://badgen.net/badge/icon/discord?icon=discord&label)](https://discord.gg/rQ7H9cSsF4) -[Documentation](https://docs.rs/zip/0.6.2/zip/) +[Documentation](https://docs.rs/zip/0.6.3/zip/) > PSA: This version of the ZIP crate will not gain any new features, > and will only be updated if major security issues are found. @@ -35,14 +35,14 @@ With all default features: ```toml [dependencies] -zip = "0.6.2" +zip = "0.6.3" ``` Without the default features: ```toml [dependencies] -zip = { version = "0.6.2", default-features = false } +zip = { version = "0.6.3", default-features = false } ``` The features available are: @@ -58,7 +58,7 @@ All of these are enabled by default. MSRV ---- -Our current Minimum Supported Rust Version is **1.54.0**. When adding features, +Our current Minimum Supported Rust Version is **1.59.0**. When adding features, we will follow these guidelines: - We will always support the latest four minor Rust versions. This gives you a 6 @@ -75,3 +75,24 @@ See the [examples directory](examples) for: * How to extract a zip file. * How to extract a single file from a zip. * How to read a zip from the standard input. + +Fuzzing +------- + +Fuzzing support is through [cargo fuzz](https://github.com/rust-fuzz/cargo-fuzz). To install cargo fuzz: + +```bash +cargo install cargo-fuzz +``` + +To list fuzz targets: + +```bash +cargo +nightly fuzz list +``` + +To start fuzzing zip extraction: + +```bash +cargo +nightly fuzz run fuzz_read +``` diff --git a/benches/read_metadata.rs b/benches/read_metadata.rs new file mode 100644 index 0000000..51f1f69 --- /dev/null +++ b/benches/read_metadata.rs @@ -0,0 +1,41 @@ +use bencher::{benchmark_group, benchmark_main}; + +use std::io::{Cursor, Write}; + +use bencher::Bencher; +use zip::{ZipArchive, ZipWriter}; + +const FILE_COUNT: usize = 15_000; +const FILE_SIZE: usize = 1024; + +fn generate_random_archive(count_files: usize, file_size: usize) -> Vec<u8> { + let data = Vec::new(); + let mut writer = ZipWriter::new(Cursor::new(data)); + let options = + zip::write::FileOptions::default().compression_method(zip::CompressionMethod::Stored); + + let bytes = vec![0u8; file_size]; + + for i in 0..count_files { + let name = format!( + "file_deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef_{}.dat", + i + ); + writer.start_file(name, options).unwrap(); + writer.write_all(&bytes).unwrap(); + } + + writer.finish().unwrap().into_inner() +} + +fn read_metadata(bench: &mut Bencher) { + let bytes = generate_random_archive(FILE_COUNT, FILE_SIZE); + + bench.iter(|| { + let archive = ZipArchive::new(Cursor::new(bytes.as_slice())).unwrap(); + archive.len() + }); +} + +benchmark_group!(benches, read_metadata); +benchmark_main!(benches); diff --git a/src/read.rs b/src/read.rs index c619f24..728ddf5 100644 --- a/src/read.rs +++ b/src/read.rs @@ -408,8 +408,16 @@ impl<R: Read + io::Seek> ZipArchive<R> { let (archive_offset, directory_start, number_of_files) = Self::get_directory_counts(&mut reader, &footer, cde_start_pos)?; - let mut files = Vec::new(); - let mut names_map = HashMap::new(); + // If the parsed number of files is greater than the offset then + // something fishy is going on and we shouldn't trust number_of_files. + let file_capacity = if number_of_files > cde_start_pos as usize { + 0 + } else { + number_of_files + }; + + let mut files = Vec::with_capacity(file_capacity); + let mut names_map = HashMap::with_capacity(file_capacity); if reader.seek(io::SeekFrom::Start(directory_start)).is_err() { return Err(ZipError::InvalidArchive( @@ -639,7 +647,7 @@ pub(crate) fn central_header_to_zip_file<R: Read + io::Seek>( reader: &mut R, archive_offset: u64, ) -> ZipResult<ZipFileData> { - let central_header_start = reader.seek(io::SeekFrom::Current(0))?; + let central_header_start = reader.stream_position()?; // Parse central header let signature = reader.read_u32::<LittleEndian>()?; if signature != spec::CENTRAL_DIRECTORY_HEADER_SIGNATURE { @@ -949,7 +957,7 @@ impl<'a> ZipFile<'a> { match self.data.system { System::Unix => Some(self.data.external_attributes >> 16), System::Dos => { - // Interpret MSDOS directory bit + // Interpret MS-DOS directory bit let mut mode = if 0x10 == (self.data.external_attributes & 0x10) { ffi::S_IFDIR | 0o0775 } else { @@ -1267,4 +1275,36 @@ mod test { ); } } + + /// test case to ensure we don't preemptively over allocate based on the + /// declared number of files in the CDE of an invalid zip when the number of + /// files declared is more than the alleged offset in the CDE + #[test] + fn invalid_cde_number_of_files_allocation_smaller_offset() { + use super::ZipArchive; + use std::io; + + let mut v = Vec::new(); + v.extend_from_slice(include_bytes!( + "../tests/data/invalid_cde_number_of_files_allocation_smaller_offset.zip" + )); + let reader = ZipArchive::new(io::Cursor::new(v)); + assert!(reader.is_err()); + } + + /// test case to ensure we don't preemptively over allocate based on the + /// declared number of files in the CDE of an invalid zip when the number of + /// files declared is less than the alleged offset in the CDE + #[test] + fn invalid_cde_number_of_files_allocation_greater_offset() { + use super::ZipArchive; + use std::io; + + let mut v = Vec::new(); + v.extend_from_slice(include_bytes!( + "../tests/data/invalid_cde_number_of_files_allocation_greater_offset.zip" + )); + let reader = ZipArchive::new(io::Cursor::new(v)); + assert!(reader.is_err()); + } } diff --git a/src/write.rs b/src/write.rs index 551b4e3..61ce378 100644 --- a/src/write.rs +++ b/src/write.rs @@ -174,7 +174,11 @@ impl FileOptions { /// /// The format is represented with unix-style permissions. /// The default is `0o644`, which represents `rw-r--r--` for files, - /// and `0o755`, which represents `rwxr-xr-x` for directories + /// and `0o755`, which represents `rwxr-xr-x` for directories. + /// + /// This method only preserves the file permissions bits (via a `& 0o777`) and discards + /// higher file mode bits. So it cannot be used to denote an entry as a directory, + /// symlink, or other special file type. #[must_use] pub fn unix_permissions(mut self, mode: u32) -> FileOptions { self.permissions = Some(mode & 0o777); @@ -348,7 +352,7 @@ impl<W: Write + io::Seek> ZipWriter<W> { { let writer = self.inner.get_plain(); - let header_start = writer.seek(io::SeekFrom::Current(0))?; + let header_start = writer.stream_position()?; let permissions = options.permissions.unwrap_or(0o100644); let mut file = ZipFileData { @@ -375,7 +379,7 @@ impl<W: Write + io::Seek> ZipWriter<W> { }; write_local_file_header(writer, &file)?; - let header_end = writer.seek(io::SeekFrom::Current(0))?; + let header_end = writer.stream_position()?; self.stats.start = header_end; *file.data_start.get_mut() = header_end; @@ -404,7 +408,7 @@ impl<W: Write + io::Seek> ZipWriter<W> { file.crc32 = self.stats.hasher.clone().finalize(); file.uncompressed_size = self.stats.bytes_written; - let file_end = writer.seek(io::SeekFrom::Current(0))?; + let file_end = writer.stream_position()?; file.compressed_size = file_end - self.stats.start; update_local_file_header(writer, file)?; @@ -723,7 +727,7 @@ impl<W: Write + io::Seek> ZipWriter<W> { /// Add a directory entry, taking a Path as argument. /// - /// This function ensures that the '/' path seperator is used. It also ignores all non 'Normal' + /// This function ensures that the '/' path separator is used. It also ignores all non 'Normal' /// Components, such as a starting '/' or '..' and '.'. #[deprecated( since = "0.5.7", @@ -747,17 +751,55 @@ impl<W: Write + io::Seek> ZipWriter<W> { Ok(inner.unwrap()) } + /// Add a symlink entry. + /// + /// The zip archive will contain an entry for path `name` which is a symlink to `target`. + /// + /// No validation or normalization of the paths is performed. For best results, + /// callers should normalize `\` to `/` and ensure symlinks are relative to other + /// paths within the zip archive. + /// + /// WARNING: not all zip implementations preserve symlinks on extract. Some zip + /// implementations may materialize a symlink as a regular file, possibly with the + /// content incorrectly set to the symlink target. For maximum portability, consider + /// storing a regular file instead. + pub fn add_symlink<N, T>( + &mut self, + name: N, + target: T, + mut options: FileOptions, + ) -> ZipResult<()> + where + N: Into<String>, + T: Into<String>, + { + if options.permissions.is_none() { + options.permissions = Some(0o777); + } + *options.permissions.as_mut().unwrap() |= 0o120000; + // The symlink target is stored as file content. And compressing the target path + // likely wastes space. So always store. + options.compression_method = CompressionMethod::Stored; + + self.start_entry(name, options, None)?; + self.writing_to_file = true; + self.write_all(target.into().as_bytes())?; + self.writing_to_file = false; + + Ok(()) + } + fn finalize(&mut self) -> ZipResult<()> { self.finish_file()?; { let writer = self.inner.get_plain(); - let central_start = writer.seek(io::SeekFrom::Current(0))?; + let central_start = writer.stream_position()?; for file in self.files.iter() { write_central_directory_header(writer, file)?; } - let central_size = writer.seek(io::SeekFrom::Current(0))? - central_start; + let central_size = writer.stream_position()? - central_start; if self.files.len() > spec::ZIP64_ENTRY_THR || central_size.max(central_start) > spec::ZIP64_BYTES_THR @@ -1286,6 +1328,13 @@ mod test { } #[test] + fn unix_permissions_bitmask() { + // unix_permissions() throws away upper bits. + let options = FileOptions::default().unix_permissions(0o120777); + assert_eq!(options.permissions, Some(0o777)); + } + + #[test] fn write_zip_dir() { let mut writer = ZipWriter::new(io::Cursor::new(Vec::new())); writer @@ -1314,6 +1363,67 @@ mod test { } #[test] + fn write_symlink_simple() { + let mut writer = ZipWriter::new(io::Cursor::new(Vec::new())); + writer + .add_symlink( + "name", + "target", + FileOptions::default().last_modified_time( + DateTime::from_date_and_time(2018, 8, 15, 20, 45, 6).unwrap(), + ), + ) + .unwrap(); + assert!(writer + .write(b"writing to a symlink is not allowed and will not write any data") + .is_err()); + let result = writer.finish().unwrap(); + assert_eq!(result.get_ref().len(), 112); + assert_eq!( + *result.get_ref(), + &[ + 80u8, 75, 3, 4, 20, 0, 0, 0, 0, 0, 163, 165, 15, 77, 252, 47, 111, 70, 6, 0, 0, 0, + 6, 0, 0, 0, 4, 0, 0, 0, 110, 97, 109, 101, 116, 97, 114, 103, 101, 116, 80, 75, 1, + 2, 46, 3, 20, 0, 0, 0, 0, 0, 163, 165, 15, 77, 252, 47, 111, 70, 6, 0, 0, 0, 6, 0, + 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 161, 0, 0, 0, 0, 110, 97, 109, 101, + 80, 75, 5, 6, 0, 0, 0, 0, 1, 0, 1, 0, 50, 0, 0, 0, 40, 0, 0, 0, 0, 0 + ] as &[u8], + ); + } + + #[test] + fn write_symlink_wonky_paths() { + let mut writer = ZipWriter::new(io::Cursor::new(Vec::new())); + writer + .add_symlink( + "directory\\link", + "/absolute/symlink\\with\\mixed/slashes", + FileOptions::default().last_modified_time( + DateTime::from_date_and_time(2018, 8, 15, 20, 45, 6).unwrap(), + ), + ) + .unwrap(); + assert!(writer + .write(b"writing to a symlink is not allowed and will not write any data") + .is_err()); + let result = writer.finish().unwrap(); + assert_eq!(result.get_ref().len(), 162); + assert_eq!( + *result.get_ref(), + &[ + 80u8, 75, 3, 4, 20, 0, 0, 0, 0, 0, 163, 165, 15, 77, 95, 41, 81, 245, 36, 0, 0, 0, + 36, 0, 0, 0, 14, 0, 0, 0, 100, 105, 114, 101, 99, 116, 111, 114, 121, 92, 108, 105, + 110, 107, 47, 97, 98, 115, 111, 108, 117, 116, 101, 47, 115, 121, 109, 108, 105, + 110, 107, 92, 119, 105, 116, 104, 92, 109, 105, 120, 101, 100, 47, 115, 108, 97, + 115, 104, 101, 115, 80, 75, 1, 2, 46, 3, 20, 0, 0, 0, 0, 0, 163, 165, 15, 77, 95, + 41, 81, 245, 36, 0, 0, 0, 36, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, + 161, 0, 0, 0, 0, 100, 105, 114, 101, 99, 116, 111, 114, 121, 92, 108, 105, 110, + 107, 80, 75, 5, 6, 0, 0, 0, 0, 1, 0, 1, 0, 60, 0, 0, 0, 80, 0, 0, 0, 0, 0 + ] as &[u8], + ); + } + + #[test] fn write_mimetype_zip() { let mut writer = ZipWriter::new(io::Cursor::new(Vec::new())); let options = FileOptions { diff --git a/tests/data/invalid_cde_number_of_files_allocation_greater_offset.zip b/tests/data/invalid_cde_number_of_files_allocation_greater_offset.zip Binary files differnew file mode 100644 index 0000000..a428ca7 --- /dev/null +++ b/tests/data/invalid_cde_number_of_files_allocation_greater_offset.zip diff --git a/tests/data/invalid_cde_number_of_files_allocation_smaller_offset.zip b/tests/data/invalid_cde_number_of_files_allocation_smaller_offset.zip Binary files differnew file mode 100644 index 0000000..2cc9007 --- /dev/null +++ b/tests/data/invalid_cde_number_of_files_allocation_smaller_offset.zip |