diff --git a/testdata/readme.samenameszip b/testdata/readme.samenameszip new file mode 100644 index 0000000..ab0dfff --- /dev/null +++ b/testdata/readme.samenameszip @@ -0,0 +1,67 @@ +# Multiple entries with the same name + +It is possible to have multiple entries in the same ZIP file, with different +properties, for example a copy of a file, and a link with the same name. It +is unclear how these conflicts should be resolved. + +A simple test script to add a file with the same entries: + +``` +#!/usr/bin/env python3 + +import zipfile + +z = zipfile.ZipInfo(4*'a') +contents = 10*b'c' +bla = zipfile.ZipFile('/tmp/same-names.zip', mode='w') +bla.writestr(z, contents) +bla.writestr(z, contents) +bla.writestr(z, contents) +bla.close() +``` + +This script adds a file called `aaaa` to an archive three times. When running +this script Python's `zipfile` module issues a warning: + +``` +$ python3 test.py +/usr/lib64/python3.10/zipfile.py:1519: UserWarning: Duplicate name: 'aaaa' + return self._open_to_write(zinfo, force_zip64=force_zip64) +``` + +but it will write the file with three files, as can be seen when running +`zipinfo`: + +``` +$ zipinfo same-names.zip +Archive: same-names.zip +Zip file size: 304 bytes, number of entries: 3 +?rw------- 2.0 unx 10 b- stor 80-Jan-01 00:00 aaaa +?rw------- 2.0 unx 10 b- stor 80-Jan-01 00:00 aaaa +?rw------- 2.0 unx 10 b- stor 80-Jan-01 00:00 aaaa +3 files, 30 bytes uncompressed, 30 bytes compressed: 0.0% +``` + +`unzip` refuses to unpack the file more than once, except when forced: + +``` +$ unzip same-names.zip +Archive: same-names.zip + extracting: aaaa +error: invalid zip file with overlapped components (possible zip bomb) + To unzip the file anyway, rerun the command with UNZIP_DISABLE_ZIPBOMB_DETECTION=TRUE environmnent variable +``` + +When the environment variable is set the user will be asked what to do (here +the `All` option was chosen): + +``` +$ UNZIP_DISABLE_ZIPBOMB_DETECTION=TRUE unzip same-names.zip +Archive: same-names.zip +replace aaaa? [y]es, [n]o, [A]ll, [N]one, [r]ename: A + extracting: aaaa + extracting: aaaa + extracting: aaaa +``` + +`p7zip` will also query the user whether to overwrite the files or not. diff --git a/testdata/same-names.zip b/testdata/same-names.zip new file mode 100644 index 0000000..af0873f Binary files /dev/null and b/testdata/same-names.zip differ diff --git a/ziplinter/src/snapshots/ziplinter__test__same-names.zip.snap b/ziplinter/src/snapshots/ziplinter__test__same-names.zip.snap new file mode 100644 index 0000000..f9ebd43 --- /dev/null +++ b/ziplinter/src/snapshots/ziplinter__test__same-names.zip.snap @@ -0,0 +1,228 @@ +--- +source: ziplinter/src/lib.rs +expression: result +--- +{ + "comment": "", + "contents": [ + { + "central": { + "comment": "", + "compressed_size": 10, + "crc32": 4044738111, + "creator_version": { + "host_system": "Unix", + "version": 20 + }, + "disk_nbr_start": 0, + "external_attrs": 25165824, + "extra": [], + "flags": 0, + "header_offset": 88, + "internal_attrs": 0, + "method": "Store", + "mode": 384, + "modified": "1980-01-01T00:00:00Z", + "name": "aaaa", + "reader_version": { + "host_system": "MsDos", + "version": 20 + }, + "uncompressed_size": 10 + }, + "local": { + "accessed": null, + "compressed_size": 10, + "crc32": 4044738111, + "created": null, + "extra": [], + "flags": 0, + "gid": null, + "header_offset": 0, + "method": "Store", + "method_specific": "None", + "mode": 0, + "modified": "1980-01-01T00:00:00Z", + "name": "aaaa", + "reader_version": { + "host_system": "MsDos", + "version": 20 + }, + "uid": null, + "uncompressed_size": 10 + } + }, + { + "central": { + "comment": "", + "compressed_size": 10, + "crc32": 4044738111, + "creator_version": { + "host_system": "Unix", + "version": 20 + }, + "disk_nbr_start": 0, + "external_attrs": 25165824, + "extra": [], + "flags": 0, + "header_offset": 88, + "internal_attrs": 0, + "method": "Store", + "mode": 384, + "modified": "1980-01-01T00:00:00Z", + "name": "aaaa", + "reader_version": { + "host_system": "MsDos", + "version": 20 + }, + "uncompressed_size": 10 + }, + "local": { + "accessed": null, + "compressed_size": 10, + "crc32": 4044738111, + "created": null, + "extra": [], + "flags": 0, + "gid": null, + "header_offset": 0, + "method": "Store", + "method_specific": "None", + "mode": 0, + "modified": "1980-01-01T00:00:00Z", + "name": "aaaa", + "reader_version": { + "host_system": "MsDos", + "version": 20 + }, + "uid": null, + "uncompressed_size": 10 + } + }, + { + "central": { + "comment": "", + "compressed_size": 10, + "crc32": 4044738111, + "creator_version": { + "host_system": "Unix", + "version": 20 + }, + "disk_nbr_start": 0, + "external_attrs": 25165824, + "extra": [], + "flags": 0, + "header_offset": 88, + "internal_attrs": 0, + "method": "Store", + "mode": 384, + "modified": "1980-01-01T00:00:00Z", + "name": "aaaa", + "reader_version": { + "host_system": "MsDos", + "version": 20 + }, + "uncompressed_size": 10 + }, + "local": { + "accessed": null, + "compressed_size": 10, + "crc32": 4044738111, + "created": null, + "extra": [], + "flags": 0, + "gid": null, + "header_offset": 0, + "method": "Store", + "method_specific": "None", + "mode": 0, + "modified": "1980-01-01T00:00:00Z", + "name": "aaaa", + "reader_version": { + "host_system": "MsDos", + "version": 20 + }, + "uid": null, + "uncompressed_size": 10 + } + } + ], + "encoding": "Utf8", + "eocd": { + "dir": { + "inner": { + "dir_disk_nbr": 0, + "dir_records_this_disk": 3, + "directory_offset": 132, + "directory_records": 3, + "directory_size": 150, + "disk_nbr": 0 + }, + "offset": 282 + }, + "dir64": null, + "global_offset": 0 + }, + "parsed_ranges": [ + { + "contains": "end of central directory record", + "end": 304, + "start": 282 + }, + { + "contains": "central directory header", + "end": 182, + "filename": "aaaa", + "start": 132 + }, + { + "contains": "central directory header", + "end": 232, + "filename": "aaaa", + "start": 182 + }, + { + "contains": "central directory header", + "end": 282, + "filename": "aaaa", + "start": 282 + }, + { + "contains": "local file header", + "end": 122, + "filename": "aaaa", + "start": 88 + }, + { + "contains": "file data", + "end": 132, + "filename": "aaaa", + "start": 122 + }, + { + "contains": "local file header", + "end": 122, + "filename": "aaaa", + "start": 88 + }, + { + "contains": "file data", + "end": 132, + "filename": "aaaa", + "start": 122 + }, + { + "contains": "local file header", + "end": 122, + "filename": "aaaa", + "start": 88 + }, + { + "contains": "file data", + "end": 132, + "filename": "aaaa", + "start": 122 + } + ], + "size": 304 +}