diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d5038b..0d99ab0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +## Zip 2.0.1 + +* Fixed corruption of large entries when zip64 is used. [Issue + 111](https://github.com/mrkkrp/zip/issues/111). + ## Zip 2.0.0 * Unified `BZip2Unsupported` and `ZstdUnsupported` into a single data diff --git a/Codec/Archive/Zip/Internal.hs b/Codec/Archive/Zip/Internal.hs index d6d2164..96c4dc3 100644 --- a/Codec/Archive/Zip/Internal.hs +++ b/Codec/Archive/Zip/Internal.hs @@ -779,11 +779,16 @@ makeZip64ExtraField :: -- | Resulting representation ByteString makeZip64ExtraField headerType Zip64ExtraField {..} = runPut $ do - when (headerType == LocalHeader || z64efUncompressedSize >= ffffffff) $ - putWord64le (fromIntegral z64efUncompressedSize) -- uncompressed size - when (headerType == LocalHeader || z64efCompressedSize >= ffffffff) $ - putWord64le (fromIntegral z64efCompressedSize) -- compressed size - when (headerType == CentralDirHeader && z64efOffset >= ffffffff) $ + case headerType of + LocalHeader -> do + putWord64le (fromIntegral z64efUncompressedSize) -- uncompressed size + putWord64le (fromIntegral z64efCompressedSize) -- compressed size + CentralDirHeader -> do + when (z64efUncompressedSize >= ffffffff) $ + putWord64le (fromIntegral z64efUncompressedSize) -- uncompressed size + when (z64efCompressedSize >= ffffffff) $ + putWord64le (fromIntegral z64efCompressedSize) -- compressed size + when (z64efOffset >= ffffffff) $ putWord64le (fromIntegral z64efOffset) -- offset of local file header -- | Create 'ByteString' representing an extra field. @@ -810,7 +815,8 @@ putHeader :: EntryDescription -> Put putHeader headerType s entry@EntryDescription {..} = do - let isCentralDirHeader = headerType == CentralDirHeader + let isLocalHeader = headerType == LocalHeader + isCentralDirHeader = headerType == CentralDirHeader putWord32le (bool 0x04034b50 0x02014b50 isCentralDirHeader) -- ↑ local/central file header signature when isCentralDirHeader $ @@ -842,7 +848,7 @@ putHeader headerType s entry@EntryDescription {..} = do } extraField = B.take 0xffff . runPut . putExtraField $ - if needsZip64 entry + if needsZip64 entry || isLocalHeader then M.insert 1 zip64ef edExtraField else edExtraField putWord16le (fromIntegral $ B.length extraField) -- extra field length diff --git a/tests/Main.hs b/tests/Main.hs index c625065..c85dfe8 100644 --- a/tests/Main.hs +++ b/tests/Main.hs @@ -462,7 +462,7 @@ checkEntrySpec = do it "does not pass the check" $ \path -> property $ \b s -> not (B.null b) ==> do - let headerLength = 30 + (B.length . T.encodeUtf8 . getEntryName $ s) + let headerLength = 50 + (B.length . T.encodeUtf8 . getEntryName $ s) localFileHeaderOffset <- createArchive path $ do addEntry Store b s commit