diff options
Diffstat (limited to 'third_party/rust/zip/tests')
16 files changed, 666 insertions, 0 deletions
diff --git a/third_party/rust/zip/tests/aes_encryption.rs b/third_party/rust/zip/tests/aes_encryption.rs new file mode 100644 index 0000000000..4b393ebf96 --- /dev/null +++ b/third_party/rust/zip/tests/aes_encryption.rs @@ -0,0 +1,80 @@ +#![cfg(feature = "aes-crypto")] + +use std::io::{self, Read}; +use zip::ZipArchive; + +const SECRET_CONTENT: &str = "Lorem ipsum dolor sit amet"; + +const PASSWORD: &[u8] = b"helloworld"; + +#[test] +fn aes256_encrypted_uncompressed_file() { + let mut v = Vec::new(); + v.extend_from_slice(include_bytes!("data/aes_archive.zip")); + let mut archive = ZipArchive::new(io::Cursor::new(v)).expect("couldn't open test zip file"); + + let mut file = archive + .by_name_decrypt("secret_data_256_uncompressed", PASSWORD) + .expect("couldn't find file in archive") + .expect("invalid password"); + assert_eq!("secret_data_256_uncompressed", file.name()); + + let mut content = String::new(); + file.read_to_string(&mut content) + .expect("couldn't read encrypted file"); + assert_eq!(SECRET_CONTENT, content); +} + +#[test] +fn aes256_encrypted_file() { + let mut v = Vec::new(); + v.extend_from_slice(include_bytes!("data/aes_archive.zip")); + let mut archive = ZipArchive::new(io::Cursor::new(v)).expect("couldn't open test zip file"); + + let mut file = archive + .by_name_decrypt("secret_data_256", PASSWORD) + .expect("couldn't find file in archive") + .expect("invalid password"); + assert_eq!("secret_data_256", file.name()); + + let mut content = String::new(); + file.read_to_string(&mut content) + .expect("couldn't read encrypted and compressed file"); + assert_eq!(SECRET_CONTENT, content); +} + +#[test] +fn aes192_encrypted_file() { + let mut v = Vec::new(); + v.extend_from_slice(include_bytes!("data/aes_archive.zip")); + let mut archive = ZipArchive::new(io::Cursor::new(v)).expect("couldn't open test zip file"); + + let mut file = archive + .by_name_decrypt("secret_data_192", PASSWORD) + .expect("couldn't find file in archive") + .expect("invalid password"); + assert_eq!("secret_data_192", file.name()); + + let mut content = String::new(); + file.read_to_string(&mut content) + .expect("couldn't read encrypted file"); + assert_eq!(SECRET_CONTENT, content); +} + +#[test] +fn aes128_encrypted_file() { + let mut v = Vec::new(); + v.extend_from_slice(include_bytes!("data/aes_archive.zip")); + let mut archive = ZipArchive::new(io::Cursor::new(v)).expect("couldn't open test zip file"); + + let mut file = archive + .by_name_decrypt("secret_data_128", PASSWORD) + .expect("couldn't find file in archive") + .expect("invalid password"); + assert_eq!("secret_data_128", file.name()); + + let mut content = String::new(); + file.read_to_string(&mut content) + .expect("couldn't read encrypted file"); + assert_eq!(SECRET_CONTENT, content); +} diff --git a/third_party/rust/zip/tests/data/aes_archive.zip b/third_party/rust/zip/tests/data/aes_archive.zip Binary files differnew file mode 100644 index 0000000000..4cf1fd21ec --- /dev/null +++ b/third_party/rust/zip/tests/data/aes_archive.zip diff --git a/third_party/rust/zip/tests/data/comment_garbage.zip b/third_party/rust/zip/tests/data/comment_garbage.zip Binary files differnew file mode 100644 index 0000000000..f6a289e817 --- /dev/null +++ b/third_party/rust/zip/tests/data/comment_garbage.zip diff --git a/third_party/rust/zip/tests/data/files_and_dirs.zip b/third_party/rust/zip/tests/data/files_and_dirs.zip Binary files differnew file mode 100644 index 0000000000..c444078a4a --- /dev/null +++ b/third_party/rust/zip/tests/data/files_and_dirs.zip diff --git a/third_party/rust/zip/tests/data/invalid_cde_number_of_files_allocation_greater_offset.zip b/third_party/rust/zip/tests/data/invalid_cde_number_of_files_allocation_greater_offset.zip Binary files differnew file mode 100644 index 0000000000..a428ca7e36 --- /dev/null +++ b/third_party/rust/zip/tests/data/invalid_cde_number_of_files_allocation_greater_offset.zip diff --git a/third_party/rust/zip/tests/data/invalid_cde_number_of_files_allocation_smaller_offset.zip b/third_party/rust/zip/tests/data/invalid_cde_number_of_files_allocation_smaller_offset.zip Binary files differnew file mode 100644 index 0000000000..2cc90073f6 --- /dev/null +++ b/third_party/rust/zip/tests/data/invalid_cde_number_of_files_allocation_smaller_offset.zip diff --git a/third_party/rust/zip/tests/data/invalid_offset.zip b/third_party/rust/zip/tests/data/invalid_offset.zip Binary files differnew file mode 100644 index 0000000000..9ff2e07fa8 --- /dev/null +++ b/third_party/rust/zip/tests/data/invalid_offset.zip diff --git a/third_party/rust/zip/tests/data/invalid_offset2.zip b/third_party/rust/zip/tests/data/invalid_offset2.zip Binary files differnew file mode 100644 index 0000000000..944c611df1 --- /dev/null +++ b/third_party/rust/zip/tests/data/invalid_offset2.zip diff --git a/third_party/rust/zip/tests/data/mimetype.zip b/third_party/rust/zip/tests/data/mimetype.zip Binary files differnew file mode 100644 index 0000000000..2d651cbeb3 --- /dev/null +++ b/third_party/rust/zip/tests/data/mimetype.zip diff --git a/third_party/rust/zip/tests/data/zip64_demo.zip b/third_party/rust/zip/tests/data/zip64_demo.zip Binary files differnew file mode 100644 index 0000000000..f2ceee303e --- /dev/null +++ b/third_party/rust/zip/tests/data/zip64_demo.zip diff --git a/third_party/rust/zip/tests/end_to_end.rs b/third_party/rust/zip/tests/end_to_end.rs new file mode 100644 index 0000000000..25d0c54d0b --- /dev/null +++ b/third_party/rust/zip/tests/end_to_end.rs @@ -0,0 +1,205 @@ +use byteorder::{LittleEndian, WriteBytesExt}; +use std::collections::HashSet; +use std::io::prelude::*; +use std::io::{Cursor, Seek}; +use std::iter::FromIterator; +use zip::write::FileOptions; +use zip::{CompressionMethod, SUPPORTED_COMPRESSION_METHODS}; + +// This test asserts that after creating a zip file, then reading its contents back out, +// the extracted data will *always* be exactly the same as the original data. +#[test] +fn end_to_end() { + for &method in SUPPORTED_COMPRESSION_METHODS { + let file = &mut Cursor::new(Vec::new()); + + println!("Writing file with {} compression", method); + write_test_archive(file, method).expect("Couldn't write test zip archive"); + + println!("Checking file contents"); + check_archive_file(file, ENTRY_NAME, Some(method), LOREM_IPSUM); + } +} + +// This test asserts that after copying a `ZipFile` to a new `ZipWriter`, then reading its +// contents back out, the extracted data will *always* be exactly the same as the original data. +#[test] +fn copy() { + for &method in SUPPORTED_COMPRESSION_METHODS { + let src_file = &mut Cursor::new(Vec::new()); + write_test_archive(src_file, method).expect("Couldn't write to test file"); + + let mut tgt_file = &mut Cursor::new(Vec::new()); + + { + let mut src_archive = zip::ZipArchive::new(src_file).unwrap(); + let mut zip = zip::ZipWriter::new(&mut tgt_file); + + { + let file = src_archive + .by_name(ENTRY_NAME) + .expect("Missing expected file"); + + zip.raw_copy_file(file).expect("Couldn't copy file"); + } + + { + let file = src_archive + .by_name(ENTRY_NAME) + .expect("Missing expected file"); + + zip.raw_copy_file_rename(file, COPY_ENTRY_NAME) + .expect("Couldn't copy and rename file"); + } + } + + let mut tgt_archive = zip::ZipArchive::new(tgt_file).unwrap(); + + check_archive_file_contents(&mut tgt_archive, ENTRY_NAME, LOREM_IPSUM); + check_archive_file_contents(&mut tgt_archive, COPY_ENTRY_NAME, LOREM_IPSUM); + } +} + +// This test asserts that after appending to a `ZipWriter`, then reading its contents back out, +// both the prior data and the appended data will be exactly the same as their originals. +#[test] +fn append() { + for &method in SUPPORTED_COMPRESSION_METHODS { + let mut file = &mut Cursor::new(Vec::new()); + write_test_archive(file, method).expect("Couldn't write to test file"); + + { + let mut zip = zip::ZipWriter::new_append(&mut file).unwrap(); + zip.start_file( + COPY_ENTRY_NAME, + FileOptions::default().compression_method(method), + ) + .unwrap(); + zip.write_all(LOREM_IPSUM).unwrap(); + zip.finish().unwrap(); + } + + let mut zip = zip::ZipArchive::new(&mut file).unwrap(); + check_archive_file_contents(&mut zip, ENTRY_NAME, LOREM_IPSUM); + check_archive_file_contents(&mut zip, COPY_ENTRY_NAME, LOREM_IPSUM); + } +} + +// Write a test zip archive to buffer. +fn write_test_archive( + file: &mut Cursor<Vec<u8>>, + method: CompressionMethod, +) -> zip::result::ZipResult<()> { + let mut zip = zip::ZipWriter::new(file); + + zip.add_directory("test/", Default::default())?; + + let options = FileOptions::default() + .compression_method(method) + .unix_permissions(0o755); + + zip.start_file("test/☃.txt", options)?; + zip.write_all(b"Hello, World!\n")?; + + zip.start_file_with_extra_data("test_with_extra_data/🐢.txt", options)?; + zip.write_u16::<LittleEndian>(0xbeef)?; + zip.write_u16::<LittleEndian>(EXTRA_DATA.len() as u16)?; + zip.write_all(EXTRA_DATA)?; + zip.end_extra_data()?; + zip.write_all(b"Hello, World! Again.\n")?; + + zip.start_file(ENTRY_NAME, options)?; + zip.write_all(LOREM_IPSUM)?; + + zip.finish()?; + Ok(()) +} + +// Load an archive from buffer and check for test data. +fn check_test_archive<R: Read + Seek>(zip_file: R) -> zip::result::ZipResult<zip::ZipArchive<R>> { + let mut archive = zip::ZipArchive::new(zip_file).unwrap(); + + // Check archive contains expected file names. + { + let expected_file_names = [ + "test/", + "test/☃.txt", + "test_with_extra_data/🐢.txt", + ENTRY_NAME, + ]; + let expected_file_names = HashSet::from_iter(expected_file_names.iter().copied()); + let file_names = archive.file_names().collect::<HashSet<_>>(); + assert_eq!(file_names, expected_file_names); + } + + // Check an archive file for extra data field contents. + { + let file_with_extra_data = archive.by_name("test_with_extra_data/🐢.txt")?; + let mut extra_data = Vec::new(); + extra_data.write_u16::<LittleEndian>(0xbeef)?; + extra_data.write_u16::<LittleEndian>(EXTRA_DATA.len() as u16)?; + extra_data.write_all(EXTRA_DATA)?; + assert_eq!(file_with_extra_data.extra_data(), extra_data.as_slice()); + } + + Ok(archive) +} + +// Read a file in the archive as a string. +fn read_archive_file<R: Read + Seek>( + archive: &mut zip::ZipArchive<R>, + name: &str, +) -> zip::result::ZipResult<String> { + let mut file = archive.by_name(name)?; + + let mut contents = String::new(); + file.read_to_string(&mut contents).unwrap(); + + Ok(contents) +} + +// Check a file in the archive contains expected data and properties. +fn check_archive_file( + zip_file: &mut Cursor<Vec<u8>>, + name: &str, + expected_method: Option<CompressionMethod>, + expected_data: &[u8], +) { + let mut archive = check_test_archive(zip_file).unwrap(); + + if let Some(expected_method) = expected_method { + // Check the file's compression method. + let file = archive.by_name(name).unwrap(); + let real_method = file.compression(); + + assert_eq!( + expected_method, real_method, + "File does not have expected compression method" + ); + } + + check_archive_file_contents(&mut archive, name, expected_data); +} + +// Check a file in the archive contains the given data. +fn check_archive_file_contents<R: Read + Seek>( + archive: &mut zip::ZipArchive<R>, + name: &str, + expected: &[u8], +) { + let file_contents: String = read_archive_file(archive, name).unwrap(); + assert_eq!(file_contents.as_bytes(), expected); +} + +const LOREM_IPSUM : &[u8] = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit. In tellus elit, tristique vitae mattis egestas, ultricies vitae risus. Quisque sit amet quam ut urna aliquet +molestie. Proin blandit ornare dui, a tempor nisl accumsan in. Praesent a consequat felis. Morbi metus diam, auctor in auctor vel, feugiat id odio. Curabitur ex ex, +dictum quis auctor quis, suscipit id lorem. Aliquam vestibulum dolor nec enim vehicula, porta tristique augue tincidunt. Vivamus ut gravida est. Sed pellentesque, dolor +vitae tristique consectetur, neque lectus pulvinar dui, sed feugiat purus diam id lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per +inceptos himenaeos. Maecenas feugiat velit in ex ultrices scelerisque id id neque. +"; + +const EXTRA_DATA: &[u8] = b"Extra Data"; + +const ENTRY_NAME: &str = "test/lorem_ipsum.txt"; + +const COPY_ENTRY_NAME: &str = "test/lorem_ipsum_renamed.txt"; diff --git a/third_party/rust/zip/tests/invalid_date.rs b/third_party/rust/zip/tests/invalid_date.rs new file mode 100644 index 0000000000..3f24e2514d --- /dev/null +++ b/third_party/rust/zip/tests/invalid_date.rs @@ -0,0 +1,24 @@ +use std::io::Cursor; +use zip::read::ZipArchive; + +const BUF: &[u8] = &[ + 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x1c, 0x00, 0x69, 0x6e, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2f, + 0x55, 0x54, 0x09, 0x00, 0x03, 0xf4, 0x5c, 0x88, 0x5a, 0xf4, 0x5c, 0x88, 0x5a, 0x75, 0x78, 0x0b, + 0x00, 0x01, 0x04, 0xe8, 0x03, 0x00, 0x00, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, + 0x1e, 0x03, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, // time part: 0 seconds, 0 minutes, 0 hours + 0x00, 0x00, // date part: day 0 (invalid), month 0 (invalid), year 0 (1980) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0xed, 0x41, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6e, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2f, + 0x55, 0x54, 0x05, 0x00, 0x03, 0xf4, 0x5c, 0x88, 0x5a, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xe8, + 0x03, 0x00, 0x00, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x01, 0x00, 0x58, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, +]; + +#[test] +fn invalid_date() { + let _archive = ZipArchive::new(Cursor::new(BUF)).unwrap(); +} diff --git a/third_party/rust/zip/tests/issue_234.rs b/third_party/rust/zip/tests/issue_234.rs new file mode 100644 index 0000000000..bd01d1d08a --- /dev/null +++ b/third_party/rust/zip/tests/issue_234.rs @@ -0,0 +1,31 @@ +use zip::result::ZipError; + +const BUF: &[u8] = &[ + 0, 80, 75, 1, 2, 127, 120, 0, 3, 3, 75, 80, 232, 3, 0, 0, 0, 0, 0, 0, 3, 0, 1, 0, 7, 0, 0, 0, + 0, 65, 0, 1, 0, 0, 0, 4, 0, 0, 224, 255, 0, 255, 255, 255, 255, 255, 255, 20, 39, 221, 221, + 221, 221, 221, 221, 205, 221, 221, 221, 42, 221, 221, 221, 221, 221, 221, 221, 221, 38, 34, 34, + 219, 80, 75, 5, 6, 0, 0, 0, 0, 5, 96, 0, 1, 71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 234, 236, 124, + 221, 221, 37, 221, 221, 221, 221, 221, 129, 4, 0, 0, 221, 221, 80, 75, 1, 2, 127, 120, 0, 4, 0, + 0, 2, 127, 120, 0, 79, 75, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, + 234, 0, 0, 0, 3, 8, 4, 232, 3, 0, 0, 0, 255, 255, 255, 255, 1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 3, 0, + 221, 209, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 58, 58, 42, 75, 9, 2, 127, + 120, 0, 99, 99, 99, 99, 99, 99, 94, 7, 0, 0, 0, 0, 0, 0, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 7, 0, 0, 211, 211, 211, 211, 124, 236, 99, 99, 99, 94, 7, 0, 0, 0, 0, 0, 0, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 7, 0, 0, 211, 211, 211, 211, 124, 236, 234, 0, 0, 0, 3, 8, + 0, 0, 0, 12, 0, 0, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0, 0, 0, 58, 58, 58, 42, 175, 221, 253, 221, + 221, 221, 221, 221, 80, 75, 9, 2, 127, 120, 0, 99, 99, 99, 99, 99, 99, 94, 7, 0, 0, 0, 0, 0, 0, + 213, 213, 213, 213, 213, 213, 213, 213, 213, 7, 0, 0, 211, 211, 211, 211, 124, 236, 221, 221, + 221, 221, 221, 80, 75, 9, 2, 127, 120, 0, 99, 99, 99, 99, 99, 99, 94, 7, 0, 0, 0, 0, 0, 0, 213, + 213, 213, 213, 213, 213, 213, 213, 213, 7, 0, 0, 211, 211, 211, 211, 124, 236, +]; + +#[test] +fn invalid_header() { + let reader = std::io::Cursor::new(&BUF); + let archive = zip::ZipArchive::new(reader); + match archive { + Err(ZipError::InvalidArchive(_)) => {} + value => panic!("Unexpected value: {:?}", value), + } +} diff --git a/third_party/rust/zip/tests/zip64_large.rs b/third_party/rust/zip/tests/zip64_large.rs new file mode 100644 index 0000000000..3d10a3181e --- /dev/null +++ b/third_party/rust/zip/tests/zip64_large.rs @@ -0,0 +1,211 @@ +// The following is a hexdump of a zip64 file containing the following files: +// zero4400: 4400 MB of zeroes +// zero100: 100 MB of zeroes +// zero4400_2: 4400 MB of zeroes +// +// 00000000 50 4b 03 04 2d 00 00 00 00 00 1b 6e 51 4d 66 82 |PK..-......nQMf.| +// 00000010 13 da ff ff ff ff ff ff ff ff 08 00 30 00 7a 65 |............0.ze| +// 00000020 72 6f 34 34 30 30 55 54 09 00 03 a5 21 c7 5b db |ro4400UT....!.[.| +// 00000030 21 c7 5b 75 78 0b 00 01 04 e8 03 00 00 04 e8 03 |!.[ux...........| +// 00000040 00 00 01 00 10 00 00 00 00 13 01 00 00 00 00 00 |................| +// 00000050 00 13 01 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +// 00000060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +// * +// 113000050 00 00 00 00 00 00 50 4b 03 04 0a 00 00 00 00 00 |......PK........| +// 113000060 2b 6e 51 4d 98 23 28 4b 00 00 40 06 00 00 40 06 |+nQM.#(K..@...@.| +// 113000070 07 00 1c 00 7a 65 72 6f 31 30 30 55 54 09 00 03 |....zero100UT...| +// 113000080 c2 21 c7 5b c2 21 c7 5b 75 78 0b 00 01 04 e8 03 |.!.[.!.[ux......| +// 113000090 00 00 04 e8 03 00 00 00 00 00 00 00 00 00 00 00 |................| +// 1130000a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +// * +// 119400090 00 00 00 00 00 00 00 50 4b 03 04 2d 00 00 00 00 |.......PK..-....| +// 1194000a0 00 3b 6e 51 4d 66 82 13 da ff ff ff ff ff ff ff |.;nQMf..........| +// 1194000b0 ff 0a 00 30 00 7a 65 72 6f 34 34 30 30 5f 32 55 |...0.zero4400_2U| +// 1194000c0 54 09 00 03 e2 21 c7 5b db 21 c7 5b 75 78 0b 00 |T....!.[.!.[ux..| +// 1194000d0 01 04 e8 03 00 00 04 e8 03 00 00 01 00 10 00 00 |................| +// 1194000e0 00 00 13 01 00 00 00 00 00 00 13 01 00 00 00 00 |................| +// 1194000f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +// * +// 22c4000e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50 |...............P| +// 22c4000f0 4b 01 02 1e 03 2d 00 00 00 00 00 1b 6e 51 4d 66 |K....-......nQMf| +// 22c400100 82 13 da ff ff ff ff ff ff ff ff 08 00 2c 00 00 |.............,..| +// 22c400110 00 00 00 00 00 00 00 a4 81 00 00 00 00 7a 65 72 |.............zer| +// 22c400120 6f 34 34 30 30 55 54 05 00 03 a5 21 c7 5b 75 78 |o4400UT....!.[ux| +// 22c400130 0b 00 01 04 e8 03 00 00 04 e8 03 00 00 01 00 10 |................| +// 22c400140 00 00 00 00 13 01 00 00 00 00 00 00 13 01 00 00 |................| +// 22c400150 00 50 4b 01 02 1e 03 0a 00 00 00 00 00 2b 6e 51 |.PK..........+nQ| +// 22c400160 4d 98 23 28 4b 00 00 40 06 00 00 40 06 07 00 24 |M.#(K..@...@...$| +// 22c400170 00 00 00 00 00 00 00 00 00 a4 81 ff ff ff ff 7a |...............z| +// 22c400180 65 72 6f 31 30 30 55 54 05 00 03 c2 21 c7 5b 75 |ero100UT....!.[u| +// 22c400190 78 0b 00 01 04 e8 03 00 00 04 e8 03 00 00 01 00 |x...............| +// 22c4001a0 08 00 56 00 00 13 01 00 00 00 50 4b 01 02 1e 03 |..V.......PK....| +// 22c4001b0 2d 00 00 00 00 00 3b 6e 51 4d 66 82 13 da ff ff |-.....;nQMf.....| +// 22c4001c0 ff ff ff ff ff ff 0a 00 34 00 00 00 00 00 00 00 |........4.......| +// 22c4001d0 00 00 a4 81 ff ff ff ff 7a 65 72 6f 34 34 30 30 |........zero4400| +// 22c4001e0 5f 32 55 54 05 00 03 e2 21 c7 5b 75 78 0b 00 01 |_2UT....!.[ux...| +// 22c4001f0 04 e8 03 00 00 04 e8 03 00 00 01 00 18 00 00 00 |................| +// 22c400200 00 13 01 00 00 00 00 00 00 13 01 00 00 00 97 00 |................| +// 22c400210 40 19 01 00 00 00 50 4b 06 06 2c 00 00 00 00 00 |@.....PK..,.....| +// 22c400220 00 00 1e 03 2d 00 00 00 00 00 00 00 00 00 03 00 |....-...........| +// 22c400230 00 00 00 00 00 00 03 00 00 00 00 00 00 00 27 01 |..............'.| +// 22c400240 00 00 00 00 00 00 ef 00 40 2c 02 00 00 00 50 4b |........@,....PK| +// 22c400250 06 07 00 00 00 00 16 02 40 2c 02 00 00 00 01 00 |........@,......| +// 22c400260 00 00 50 4b 05 06 00 00 00 00 03 00 03 00 27 01 |..PK..........'.| +// 22c400270 00 00 ff ff ff ff 00 00 |........| +// 22c400278 +use std::io::{self, Read, Seek, SeekFrom}; + +const BLOCK1_LENGTH: u64 = 0x60; +const BLOCK1: [u8; BLOCK1_LENGTH as usize] = [ + 0x50, 0x4b, 0x03, 0x04, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x6e, 0x51, 0x4d, 0x66, 0x82, + 0x13, 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x30, 0x00, 0x7a, 0x65, + 0x72, 0x6f, 0x34, 0x34, 0x30, 0x30, 0x55, 0x54, 0x09, 0x00, 0x03, 0xa5, 0x21, 0xc7, 0x5b, 0xdb, + 0x21, 0xc7, 0x5b, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xe8, 0x03, 0x00, 0x00, 0x04, 0xe8, 0x03, + 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x13, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +]; + +const BLOCK2_LENGTH: u64 = 0x50; +const BLOCK2: [u8; BLOCK2_LENGTH as usize] = [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2b, 0x6e, 0x51, 0x4d, 0x98, 0x23, 0x28, 0x4b, 0x00, 0x00, 0x40, 0x06, 0x00, 0x00, 0x40, 0x06, + 0x07, 0x00, 0x1c, 0x00, 0x7a, 0x65, 0x72, 0x6f, 0x31, 0x30, 0x30, 0x55, 0x54, 0x09, 0x00, 0x03, + 0xc2, 0x21, 0xc7, 0x5b, 0xc2, 0x21, 0xc7, 0x5b, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xe8, 0x03, + 0x00, 0x00, 0x04, 0xe8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +]; + +const BLOCK3_LENGTH: u64 = 0x60; +const BLOCK3: [u8; BLOCK3_LENGTH as usize] = [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x03, 0x04, 0x2d, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3b, 0x6e, 0x51, 0x4d, 0x66, 0x82, 0x13, 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x0a, 0x00, 0x30, 0x00, 0x7a, 0x65, 0x72, 0x6f, 0x34, 0x34, 0x30, 0x30, 0x5f, 0x32, 0x55, + 0x54, 0x09, 0x00, 0x03, 0xe2, 0x21, 0xc7, 0x5b, 0xdb, 0x21, 0xc7, 0x5b, 0x75, 0x78, 0x0b, 0x00, + 0x01, 0x04, 0xe8, 0x03, 0x00, 0x00, 0x04, 0xe8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x00, 0x00, +]; + +const BLOCK4_LENGTH: u64 = 0x198; +const BLOCK4: [u8; BLOCK4_LENGTH as usize] = [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, + 0x4b, 0x01, 0x02, 0x1e, 0x03, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x6e, 0x51, 0x4d, 0x66, + 0x82, 0x13, 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x2c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x81, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x65, 0x72, + 0x6f, 0x34, 0x34, 0x30, 0x30, 0x55, 0x54, 0x05, 0x00, 0x03, 0xa5, 0x21, 0xc7, 0x5b, 0x75, 0x78, + 0x0b, 0x00, 0x01, 0x04, 0xe8, 0x03, 0x00, 0x00, 0x04, 0xe8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, + 0x00, 0x50, 0x4b, 0x01, 0x02, 0x1e, 0x03, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x6e, 0x51, + 0x4d, 0x98, 0x23, 0x28, 0x4b, 0x00, 0x00, 0x40, 0x06, 0x00, 0x00, 0x40, 0x06, 0x07, 0x00, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x81, 0xff, 0xff, 0xff, 0xff, 0x7a, + 0x65, 0x72, 0x6f, 0x31, 0x30, 0x30, 0x55, 0x54, 0x05, 0x00, 0x03, 0xc2, 0x21, 0xc7, 0x5b, 0x75, + 0x78, 0x0b, 0x00, 0x01, 0x04, 0xe8, 0x03, 0x00, 0x00, 0x04, 0xe8, 0x03, 0x00, 0x00, 0x01, 0x00, + 0x08, 0x00, 0x56, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x1e, 0x03, + 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x6e, 0x51, 0x4d, 0x66, 0x82, 0x13, 0xda, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xa4, 0x81, 0xff, 0xff, 0xff, 0xff, 0x7a, 0x65, 0x72, 0x6f, 0x34, 0x34, 0x30, 0x30, + 0x5f, 0x32, 0x55, 0x54, 0x05, 0x00, 0x03, 0xe2, 0x21, 0xc7, 0x5b, 0x75, 0x78, 0x0b, 0x00, 0x01, + 0x04, 0xe8, 0x03, 0x00, 0x00, 0x04, 0xe8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x00, 0x13, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x00, 0x97, 0x00, + 0x40, 0x19, 0x01, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x06, 0x06, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1e, 0x03, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x00, 0x40, 0x2c, 0x02, 0x00, 0x00, 0x00, 0x50, 0x4b, + 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x16, 0x02, 0x40, 0x2c, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x27, 0x01, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, +]; + +const BLOCK1_START: u64 = 0x000000000; +const BLOCK2_START: u64 = 0x113000050; +const BLOCK3_START: u64 = 0x119400090; +const BLOCK4_START: u64 = 0x22c4000e0; + +const BLOCK1_END: u64 = BLOCK1_START + BLOCK1_LENGTH - 1; +const BLOCK2_END: u64 = BLOCK2_START + BLOCK2_LENGTH - 1; +const BLOCK3_END: u64 = BLOCK3_START + BLOCK3_LENGTH - 1; +const BLOCK4_END: u64 = BLOCK4_START + BLOCK4_LENGTH - 1; + +const TOTAL_LENGTH: u64 = BLOCK4_START + BLOCK4_LENGTH; + +struct Zip64File { + pointer: u64, +} + +impl Zip64File { + fn new() -> Self { + Zip64File { pointer: 0 } + } +} + +impl Seek for Zip64File { + fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { + match pos { + SeekFrom::Start(offset) => { + self.pointer = offset; + } + SeekFrom::End(offset) => { + if offset > 0 || offset < -(TOTAL_LENGTH as i64) { + return Err(io::Error::new(io::ErrorKind::Other, "Invalid seek offset")); + } + self.pointer = (TOTAL_LENGTH as i64 + offset) as u64; + } + SeekFrom::Current(offset) => { + let seekpos = self.pointer as i64 + offset; + if seekpos < 0 || seekpos as u64 > TOTAL_LENGTH { + return Err(io::Error::new(io::ErrorKind::Other, "Invalid seek offset")); + } + self.pointer = seekpos as u64; + } + } + Ok(self.pointer) + } +} + +impl Read for Zip64File { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + if self.pointer >= TOTAL_LENGTH { + return Ok(0); + } + match self.pointer { + BLOCK1_START..=BLOCK1_END => { + buf[0] = BLOCK1[(self.pointer - BLOCK1_START) as usize]; + } + BLOCK2_START..=BLOCK2_END => { + buf[0] = BLOCK2[(self.pointer - BLOCK2_START) as usize]; + } + BLOCK3_START..=BLOCK3_END => { + buf[0] = BLOCK3[(self.pointer - BLOCK3_START) as usize]; + } + BLOCK4_START..=BLOCK4_END => { + buf[0] = BLOCK4[(self.pointer - BLOCK4_START) as usize]; + } + _ => { + buf[0] = 0; + } + } + self.pointer += 1; + Ok(1) + } +} + +#[test] +fn zip64_large() { + let zipfile = Zip64File::new(); + let mut archive = zip::ZipArchive::new(zipfile).unwrap(); + let mut buf = [0u8; 32]; + + for i in 0..archive.len() { + let mut file = archive.by_index(i).unwrap(); + let outpath = file.enclosed_name().unwrap(); + println!( + "Entry {} has name \"{}\" ({} bytes)", + i, + outpath.display(), + file.size() + ); + + match file.read_exact(&mut buf) { + Ok(()) => println!("The first {} bytes are: {:?}", buf.len(), buf), + Err(e) => println!("Could not read the file: {:?}", e), + }; + } +} diff --git a/third_party/rust/zip/tests/zip_comment_garbage.rs b/third_party/rust/zip/tests/zip_comment_garbage.rs new file mode 100644 index 0000000000..ef4d975079 --- /dev/null +++ b/third_party/rust/zip/tests/zip_comment_garbage.rs @@ -0,0 +1,30 @@ +// Some zip files can contain garbage after the comment. For example, python zipfile generates +// it when opening a zip in 'a' mode: +// +// >>> from zipfile import ZipFile +// >>> with ZipFile('comment_garbage.zip', 'a') as z: +// ... z.comment = b'long comment bla bla bla' +// ... +// >>> with ZipFile('comment_garbage.zip', 'a') as z: +// ... z.comment = b'short.' +// ... +// >>> +// +// Hexdump: +// +// 00000000 50 4b 05 06 00 00 00 00 00 00 00 00 00 00 00 00 |PK..............| +// 00000010 00 00 00 00 06 00 73 68 6f 72 74 2e 6f 6d 6d 65 |......short.omme| +// 00000020 6e 74 20 62 6c 61 20 62 6c 61 20 62 6c 61 |nt bla bla bla| +// 0000002e + +use std::io; +use zip::ZipArchive; + +#[test] +fn correctly_handle_zip_with_garbage_after_comment() { + let mut v = Vec::new(); + v.extend_from_slice(include_bytes!("../tests/data/comment_garbage.zip")); + let archive = ZipArchive::new(io::Cursor::new(v)).expect("couldn't open test zip file"); + + assert_eq!(archive.comment(), "short.".as_bytes()); +} diff --git a/third_party/rust/zip/tests/zip_crypto.rs b/third_party/rust/zip/tests/zip_crypto.rs new file mode 100644 index 0000000000..6c4d6b811c --- /dev/null +++ b/third_party/rust/zip/tests/zip_crypto.rs @@ -0,0 +1,85 @@ +// The following is a hexdump of a zip file containing the following +// ZipCrypto encrypted file: +// test.txt: 35 bytes, contents: `abcdefghijklmnopqrstuvwxyz123456789`, password: `test` +// +// 00000000 50 4b 03 04 14 00 01 00 00 00 54 bd b5 50 2f 20 |PK........T..P/ | +// 00000010 79 55 2f 00 00 00 23 00 00 00 08 00 00 00 74 65 |yU/...#.......te| +// 00000020 73 74 2e 74 78 74 ca 2d 1d 27 19 19 63 43 77 9a |st.txt.-.'..cCw.| +// 00000030 71 76 c9 ec d1 6f d9 f5 22 67 b3 8f 52 b5 41 bc |qv...o.."g..R.A.| +// 00000040 5c 36 f2 1d 84 c3 c0 28 3b fd e1 70 c2 cc 0c 11 |\6.....(;..p....| +// 00000050 0c c5 95 2f a4 50 4b 01 02 3f 00 14 00 01 00 00 |.../.PK..?......| +// 00000060 00 54 bd b5 50 2f 20 79 55 2f 00 00 00 23 00 00 |.T..P/ yU/...#..| +// 00000070 00 08 00 24 00 00 00 00 00 00 00 20 00 00 00 00 |...$....... ....| +// 00000080 00 00 00 74 65 73 74 2e 74 78 74 0a 00 20 00 00 |...test.txt.. ..| +// 00000090 00 00 00 01 00 18 00 31 b2 3b bf b8 2f d6 01 31 |.......1.;../..1| +// 000000a0 b2 3b bf b8 2f d6 01 a8 c4 45 bd b8 2f d6 01 50 |.;../....E../..P| +// 000000b0 4b 05 06 00 00 00 00 01 00 01 00 5a 00 00 00 55 |K..........Z...U| +// 000000c0 00 00 00 00 00 |.....| +// 000000c5 + +use std::io::Cursor; +use std::io::Read; + +#[test] +fn encrypted_file() { + let zip_file_bytes = &mut Cursor::new(vec![ + 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x54, 0xbd, 0xb5, 0x50, 0x2f, + 0x20, 0x79, 0x55, 0x2f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74, 0x78, 0x74, 0xca, 0x2d, 0x1d, 0x27, 0x19, 0x19, 0x63, + 0x43, 0x77, 0x9a, 0x71, 0x76, 0xc9, 0xec, 0xd1, 0x6f, 0xd9, 0xf5, 0x22, 0x67, 0xb3, 0x8f, + 0x52, 0xb5, 0x41, 0xbc, 0x5c, 0x36, 0xf2, 0x1d, 0x84, 0xc3, 0xc0, 0x28, 0x3b, 0xfd, 0xe1, + 0x70, 0xc2, 0xcc, 0x0c, 0x11, 0x0c, 0xc5, 0x95, 0x2f, 0xa4, 0x50, 0x4b, 0x01, 0x02, 0x3f, + 0x00, 0x14, 0x00, 0x01, 0x00, 0x00, 0x00, 0x54, 0xbd, 0xb5, 0x50, 0x2f, 0x20, 0x79, 0x55, + 0x2f, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x08, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, + 0x2e, 0x74, 0x78, 0x74, 0x0a, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x18, + 0x00, 0x31, 0xb2, 0x3b, 0xbf, 0xb8, 0x2f, 0xd6, 0x01, 0x31, 0xb2, 0x3b, 0xbf, 0xb8, 0x2f, + 0xd6, 0x01, 0xa8, 0xc4, 0x45, 0xbd, 0xb8, 0x2f, 0xd6, 0x01, 0x50, 0x4b, 0x05, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x5a, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, + 0x00, 0x00, + ]); + + let mut archive = zip::ZipArchive::new(zip_file_bytes).unwrap(); + + assert_eq!(archive.len(), 1); //Only one file inside archive: `test.txt` + + { + // No password + let file = archive.by_index(0); + match file { + Err(zip::result::ZipError::UnsupportedArchive( + zip::result::ZipError::PASSWORD_REQUIRED, + )) => (), + Err(_) => panic!( + "Expected PasswordRequired error when opening encrypted file without password" + ), + Ok(_) => panic!("Error: Successfully opened encrypted file without password?!"), + } + } + + { + // Wrong password + let file = archive.by_index_decrypt(0, b"wrong password"); + match file { + Ok(Err(zip::result::InvalidPassword)) => (), + Err(_) => panic!( + "Expected InvalidPassword error when opening encrypted file with wrong password" + ), + Ok(Ok(_)) => panic!("Error: Successfully opened encrypted file with wrong password?!"), + } + } + + { + // Correct password, read contents + let mut file = archive + .by_index_decrypt(0, "test".as_bytes()) + .unwrap() + .unwrap(); + let file_name = file.enclosed_name().unwrap(); + assert_eq!(file_name, std::path::PathBuf::from("test.txt")); + + let mut data = Vec::new(); + file.read_to_end(&mut data).unwrap(); + assert_eq!(data, "abcdefghijklmnopqrstuvwxyz123456789".as_bytes()); + } +} |