diff --git a/testdata/readme.extra_data_before_central_directory b/testdata/readme.extra_data_before_central_directory new file mode 100644 index 0000000..135026a --- /dev/null +++ b/testdata/readme.extra_data_before_central_directory @@ -0,0 +1,66 @@ +Section 4.3.6 specifies the layout of a ZIP file: + +``` + 4.3.6 Overall .ZIP file format: + + [local file header 1] + [encryption header 1] + [file data 1] + [data descriptor 1] + . + . + . + [local file header n] + [encryption header n] + [file data n] + [data descriptor n] + [archive decryption header] + [archive extra data record] + [central directory header 1] + . + . + . + [central directory header n] + [zip64 end of central directory record] + [zip64 end of central directory locator] + [end of central directory record] +``` + +According to this layout there can be no layout between the last local file +header and the first central directory header, yet there are many files in +which this happens. As an example, Android packages store a signing block right +after the last local file header: + + + +Although this is not allowed APK files can still be unpacked, as programs use +the central directory to find the offsets to each individual file and +effectively skip the extra data. None of the regular ZIP programs seem to be +able to extract this extra data. + +To create a file with extra data only one field needs to be adapted (not +tested for ZIP64 files) in the "end of central directory" (section 4.3.16), +namely: + +``` +offset of start of central directory with respect to the starting disk number +``` + +The file `test_with_extra_data_before_central_directory.zip` is a modified +version of `test.zip` with an addition 1024 bytes added in between the last +local file header and the first central directory header. This means that the +central directory is moved an additional 1024 bytes. This can be shown by +comparing the output of `hexdump -C` for both files: + +The position of the central directory in the original file is `ba 03`: + +``` +00000470 00 00 ba 03 00 00 1a 00 54 68 69 73 20 69 73 20 |........This is | +``` + +In the new file the central directory has been moved 1024 bytes and is now +`ba 07`: + +``` +00000870 00 00 ba 07 00 00 1a 00 54 68 69 73 20 69 73 20 |........This is | +``` diff --git a/testdata/test_with_extra_data_before_central_directory.zip b/testdata/test_with_extra_data_before_central_directory.zip new file mode 100644 index 0000000..57a4263 Binary files /dev/null and b/testdata/test_with_extra_data_before_central_directory.zip differ diff --git a/ziplinter/src/snapshots/ziplinter__test__test_with_extra_data_before_central_directory.zip.snap b/ziplinter/src/snapshots/ziplinter__test__test_with_extra_data_before_central_directory.zip.snap new file mode 100644 index 0000000..b46adb6 --- /dev/null +++ b/ziplinter/src/snapshots/ziplinter__test__test_with_extra_data_before_central_directory.zip.snap @@ -0,0 +1,271 @@ +--- +source: ziplinter/src/lib.rs +expression: result +--- +{ + "comment": "This is a zipfile comment.", + "contents": [ + { + "central": { + "comment": "", + "compressed_size": 25, + "crc32": 3287144384, + "creator_version": { + "host_system": "Unix", + "version": 30 + }, + "disk_nbr_start": 0, + "external_attrs": 2175008768, + "extra": [ + 85, + 84, + 5, + 0, + 3, + 113, + 252, + 130, + 76, + 117, + 120, + 11, + 0, + 1, + 4, + 245, + 1, + 0, + 0, + 4, + 20, + 0, + 0, + 0 + ], + "flags": 0, + "header_offset": 0, + "internal_attrs": 1, + "method": "Deflate", + "mode": 420, + "modified": "2010-09-05T02:12:01Z", + "name": "test.txt", + "reader_version": { + "host_system": "MsDos", + "version": 20 + }, + "uncompressed_size": 26 + }, + "local": { + "accessed": null, + "compressed_size": 25, + "crc32": 3287144384, + "created": null, + "extra": [ + 85, + 84, + 9, + 0, + 3, + 113, + 252, + 130, + 76, + 118, + 252, + 130, + 76, + 117, + 120, + 11, + 0, + 1, + 4, + 245, + 1, + 0, + 0, + 4, + 20, + 0, + 0, + 0 + ], + "flags": 0, + "gid": 501, + "header_offset": 0, + "method": "Deflate", + "method_specific": "None", + "mode": 0, + "modified": "2010-09-05T02:12:01Z", + "name": "test.txt", + "reader_version": { + "host_system": "MsDos", + "version": 20 + }, + "uid": 501, + "uncompressed_size": 26 + } + }, + { + "central": { + "comment": "", + "compressed_size": 785, + "crc32": 1423258110, + "creator_version": { + "host_system": "Unix", + "version": 30 + }, + "disk_nbr_start": 0, + "external_attrs": 2175008768, + "extra": [ + 85, + 84, + 5, + 0, + 3, + 58, + 48, + 131, + 76, + 117, + 120, + 11, + 0, + 1, + 4, + 245, + 1, + 0, + 0, + 4, + 20, + 0, + 0, + 0 + ], + "flags": 0, + "header_offset": 91, + "internal_attrs": 0, + "method": "Store", + "mode": 420, + "modified": "2010-09-05T05:52:58Z", + "name": "gophercolor16x16.png", + "reader_version": { + "host_system": "MsDos", + "version": 10 + }, + "uncompressed_size": 785 + }, + "local": { + "accessed": null, + "compressed_size": 785, + "crc32": 1423258110, + "created": null, + "extra": [ + 85, + 84, + 9, + 0, + 3, + 58, + 48, + 131, + 76, + 59, + 48, + 131, + 76, + 117, + 120, + 11, + 0, + 1, + 4, + 245, + 1, + 0, + 0, + 4, + 20, + 0, + 0, + 0 + ], + "flags": 0, + "gid": 501, + "header_offset": 0, + "method": "Store", + "method_specific": "None", + "mode": 0, + "modified": "2010-09-05T05:52:58Z", + "name": "gophercolor16x16.png", + "reader_version": { + "host_system": "MsDos", + "version": 10 + }, + "uid": 501, + "uncompressed_size": 785 + } + } + ], + "encoding": "Utf8", + "eocd": { + "dir": { + "inner": { + "dir_disk_nbr": 0, + "dir_records_this_disk": 2, + "directory_offset": 1978, + "directory_records": 2, + "directory_size": 168, + "disk_nbr": 0 + }, + "offset": 2146 + }, + "dir64": null, + "global_offset": 0 + }, + "parsed_ranges": [ + { + "contains": "end of central directory record", + "end": 2194, + "start": 2146 + }, + { + "contains": "central directory header", + "end": 2056, + "filename": "test.txt", + "start": 1978 + }, + { + "contains": "central directory header", + "end": 2146, + "filename": "gophercolor16x16.png", + "start": 2056 + }, + { + "contains": "local file header", + "end": 66, + "filename": "test.txt", + "start": 0 + }, + { + "contains": "file data", + "end": 91, + "filename": "test.txt", + "start": 66 + }, + { + "contains": "local file header", + "end": 169, + "filename": "gophercolor16x16.png", + "start": 91 + }, + { + "contains": "file data", + "end": 954, + "filename": "gophercolor16x16.png", + "start": 169 + } + ], + "size": 2194 +}