Upgrade zip to 0.6.3

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
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 @@
     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 @@
 
     - 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
diff --git a/Android.bp b/Android.bp
index c0b2349..2e06d86 100644
--- a/Android.bp
+++ b/Android.bp
@@ -23,7 +23,7 @@
     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",
+]
diff --git a/Cargo.toml b/Cargo.toml
index fe1a031..7480ca9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -12,16 +12,30 @@
 [package]
 edition = "2018"
 name = "zip"
-version = "0.6.2"
-authors = ["Mathijs van de Nes <[email protected]>", "Marli Frost <[email protected]>", "Ryan Levick <[email protected]>"]
-description = "Library to support the reading and writing of zip files.\n"
-keywords = ["zip", "archive"]
+version = "0.6.3"
+authors = [
+    "Mathijs van de Nes <[email protected]>",
+    "Marli Frost <[email protected]>",
+    "Ryan Levick <[email protected]>",
+]
+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 @@
 version = "1.3.2"
 
 [dependencies.flate2]
-version = "1.0.22"
+version = "1.0.23"
 optional = true
 default-features = false
 
@@ -51,7 +65,7 @@
 optional = true
 
 [dependencies.pbkdf2]
-version = "0.10.1"
+version = "0.11.0"
 optional = true
 
 [dependencies.sha1]
@@ -60,12 +74,16 @@
 
 [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 = "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 <[email protected]>", "Marli Frost <[email protected]>", "Ryan Levick <[email protected]>"]
 license = "MIT"
 repository = "https://github.com/zip-rs/zip.git"
@@ -16,12 +16,12 @@
 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 @@
 [[bench]]
 name = "read_entry"
 harness = false
+
+[[bench]]
+name = "read_metadata"
+harness = false
diff --git a/METADATA b/METADATA
index c6e83c0..209aab1 100644
--- a/METADATA
+++ b/METADATA
@@ -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 @@
   }
   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
   }
 }
diff --git a/README.md b/README.md
index 7db31d4..9b3c059 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
 [![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 @@
 
 ```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 @@
 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 @@
    * 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 @@
         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 @@
     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 @@
         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 @@
             );
         }
     }
+
+    /// 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 @@
     ///
     /// 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 @@
 
         {
             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 @@
             };
             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 @@
             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 @@
 
     /// 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 @@
         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 @@
     }
 
     #[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 @@
     }
 
     #[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
new file mode 100644
index 0000000..a428ca7
--- /dev/null
+++ b/tests/data/invalid_cde_number_of_files_allocation_greater_offset.zip
Binary files differ
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
new file mode 100644
index 0000000..2cc9007
--- /dev/null
+++ b/tests/data/invalid_cde_number_of_files_allocation_smaller_offset.zip
Binary files differ