Closed AxbB36 closed 2 months ago
Thanks again for the thorough writeup! This is fixed in yauzl 3.1.2.
josh@nixos:~/dev/yauzl$ nix-run --pure -p nodejs -- node examples/compareCentralAndLocalHeaders.js ~/tmp/asdf/ffffffff-compressedSize.zip
pad
┌───────────────────────────┬──────────┬──────────┬────┐
│field │ central│ local│diff│
├───────────────────────────┼──────────┼──────────┼────┤
│versionMadeBy │ 0x31e│ -│ │
│versionNeededToExtract │ 0xa│ 0xa│ │
│generalPurposeBitFlag │ 0x0│ 0x0│ │
│compressionMethod │ 0x0│ 0x0│ │
│lastModFileTime │ 0x0│ 0x0│ │
│lastModFileDate │ 0x4ea1│ 0x4ea1│ │
│crc32 │ 0x0│ 0x0│ │
│compressedSize │0xffffffff│0xffffffff│ │
│uncompressedSize │0xffffffff│0xffffffff│ │
│fileNameLength │ 0x3│ 0x3│ │
│extraFieldLength │ 0x0│ 0x0│ │
│fileCommentLength │ 0x0│ -│ │
│internalFileAttributes │ 0x0│ -│ │
│externalFileAttributes │0x81a40000│ -│ │
│relativeOffsetOfLocalHeader│ 0x0│ -│ │
└───────────────────────────┴──────────┴──────────┴────┘
central.fileName: 706164
(local matches)
central.extraField:
(local matches)
central.comment:
josh@nixos:~/dev/yauzl$ nix-run --pure -p nodejs -- node examples/compareCentralAndLocalHeaders.js ~/tmp/asdf/ffffffff-relativeOffsetOfLocalHeader.zip
pad
┌───────────────────────────┬──────────┬──────────┬────┐
│field │ central│ local│diff│
├───────────────────────────┼──────────┼──────────┼────┤
│versionMadeBy │ 0x31e│ -│ │
│versionNeededToExtract │ 0xa│ 0xa│ │
│generalPurposeBitFlag │ 0x0│ 0x0│ │
│compressionMethod │ 0x0│ 0x0│ │
│lastModFileTime │ 0x0│ 0x0│ │
│lastModFileDate │ 0x4ea1│ 0x4ea1│ │
│crc32 │0xf86bd088│0xf86bd088│ │
│compressedSize │0xffffffde│0xffffffde│ │
│uncompressedSize │0xffffffde│0xffffffde│ │
│fileNameLength │ 0x3│ 0x3│ │
│extraFieldLength │ 0x0│ 0x0│ │
│fileCommentLength │ 0x0│ -│ │
│internalFileAttributes │ 0x0│ -│ │
│externalFileAttributes │0x81a40000│ -│ │
│relativeOffsetOfLocalHeader│ 0x0│ -│ │
└───────────────────────────┴──────────┴──────────┴────┘
central.fileName: 706164
(local matches)
central.extraField:
(local matches)
central.comment:
test.txt
┌───────────────────────────┬──────────┬──────────┬────┐
│field │ central│ local│diff│
├───────────────────────────┼──────────┼──────────┼────┤
│versionMadeBy │ 0x31e│ -│ │
│versionNeededToExtract │ 0xa│ 0xa│ │
│generalPurposeBitFlag │ 0x0│ 0x0│ │
│compressionMethod │ 0x0│ 0x0│ │
│lastModFileTime │ 0x0│ 0x0│ │
│lastModFileDate │ 0x4ea1│ 0x4ea1│ │
│crc32 │0x3bb935c6│0x3bb935c6│ │
│compressedSize │ 0x5│ 0x5│ │
│uncompressedSize │ 0x5│ 0x5│ │
│fileNameLength │ 0x8│ 0x8│ │
│extraFieldLength │ 0x0│ 0x0│ │
│fileCommentLength │ 0x0│ -│ │
│internalFileAttributes │ 0x0│ -│ │
│externalFileAttributes │0x81a40000│ -│ │
│relativeOffsetOfLocalHeader│0xffffffff│ -│ │
└───────────────────────────┴──────────┴──────────┴────┘
central.fileName: 746573742e747874
(local matches)
central.extraField:
(local matches)
central.comment:
These were excellent test cases! :100:
This issue is a companion to #108, but affects a different part of the parser. yauzl 2.10.0 cannot parse zip files whose
uncompressedSize
,compressedSize
, orrelativeOffsetOfLocalHeader
is 0xffffffff, unless the file is in Zip64 format. The relevant code is here: https://github.com/thejoshwolfe/yauzl/blob/02a5ca69c7713f6d2897cc02f2acc1df21093e3d/index.js#L333-L337When yauzl sees a 0xffffffff value in one of these fields, it assumes that the zip file must be in Zip64 format. But APPNOTE.TXT 4.4.8, 4.4.9, and 4.4.16 say (emphasis mine):
The way I interpret this statement, the logic should not be what yauzl does now:
but should instead be:
This issue is basically the same as https://github.com/golang/go/issues/31692. The difference is that Go archive/zip has a special-case workaround for the compressed size, but not the other two fields.
The test cases which follow are able to be parsed by Info-ZIP UnZip (
unzip
) and Python zipfile (python3 -m zipfile -e
). Go archive/zip can parse the uncompressed size test but not the other two.Uncompressed size test case
ffffffff-uncompressedSize.zip.gz (remove 1 layer of gzip before testing)
zipinfo -v
says:yauzl does not parse it:
Compressed size test case
It's difficult to construct a test case that has
compressedSize
= 0xffffffff anduncompressedSize
< 0xffffffff. It could plausibly happen if the compressor implements "store" mode not ascompressionMethod
0, but ascompressionMethod
8 (DEFLATE) and non-compressed blocks, which increase the compressed size slightly. The example here instead hascompressedSize
=uncompressedSize
= 0xffffffff.ffffffff-compressedSize.zip.gz.gz (remove 2 layers of gzip before testing)
zipinfo -v
says:yauzl does not parse it:
Local file header offset test case
ffffffff-relativeOffsetOfLocalHeader.zip.gz.gz (remove 2 layers of gzip before testing)
zipinfo -v
says:yauzl does not parse it: