srikanth-lingala / zip4j

A Java library for zip files and streams
Apache License 2.0
2.06k stars 310 forks source link

Adding comments to an existing zip64 file can corrupt the file #463

Closed jptx1234 closed 2 years ago

jptx1234 commented 2 years ago

The following code can reproduce the exception.

import java.io.ByteArrayInputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.CompressionLevel;

public class ZipTest {

  public static void main(String[] args) throws Exception {
    String zipFileName = "big-file.zip";

    generateTestFile(zipFileName);

    addComment(zipFileName);

    // net.lingala.zip4j.exception.ZipException: invalid signature for zip64 end of central directory record
    readZipFile(zipFileName);
  }

  private static void generateTestFile(String fileName) throws Exception {
    Files.deleteIfExists(Paths.get(fileName));

    byte[] data = new byte[1024 * 1024 * 1024];
    Arrays.fill(data, (byte) 0);

    ZipParameters commonParams = new ZipParameters();
    commonParams.setCompressionLevel(CompressionLevel.NO_COMPRESSION);

    try (ZipFile zipFile = new ZipFile(fileName)) {
      for (int i = 0; i < 5; i++) {
        ZipParameters entryParam = new ZipParameters(commonParams);
        entryParam.setFileNameInZip("file-" + i + ".dat");
        ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
        zipFile.addStream(inputStream, entryParam);
      }
    }

  }

  private static void addComment(String fileName) throws Exception {
    try (ZipFile zipFile = new ZipFile(fileName)) {
      zipFile.setComment("comment");
    }
  }

  private static void readZipFile(String fileName) throws Exception {
    try (ZipFile zipFile = new ZipFile(fileName)) {
      // net.lingala.zip4j.exception.ZipException: invalid signature for zip64 end of central directory record
      List<FileHeader> fileHeaders = zipFile.getFileHeaders();
      for (FileHeader fileHeader : fileHeaders) {
        System.out.println(fileHeader.getFileName());
      }
    }
  }

}

I checked the generated files using the command unzip -t big-file.zip and the output was as follows.

Archive:  big-file.zip
comment
error: End-of-centdir-64 signature not where expected (prepended bytes?)
  (attempting to process anyway)
warning [big-file.zip]:  1074561330 extra bytes at beginning or within zipfile
  (attempting to process anyway)
file #1:  bad zipfile offset (local header sig):  1074561330
  (attempting to re-compensate)
    testing: file-0.dat               OK
    testing: file-1.dat               OK
    testing: file-2.dat               OK
    testing: file-3.dat               OK
    testing: file-4.dat               OK
At least one error was detected in big-file.zip.

The output of command zip -FF big-file.zip --out big-file-fix.zip was as follows.

Fix archive (-FF) - salvage what can
 Found end record (EOCDR) - says expect single disk archive
  Found archive comment
Scanning for entries...
 copying: file-0.dat  (1073905669 bytes)
 copying: file-1.dat  (1073905669 bytes)
 copying: file-2.dat  (1073905669 bytes)
 copying: file-3.dat  (1073905669 bytes)
 copying: file-4.dat  (1073905669 bytes)
Central Directory found...
Zip64 EOCDR found ( 1 5369528937)...
Zip64 EOCDL found ( 1 5369528993)...
EOCDR found ( 1 5369529013)...
srikanth-lingala commented 2 years ago

Thank you for the detailed bug report. I fixed the issue and will include the fix in the next release

srikanth-lingala commented 2 years ago

Fix included in v2.11.2 released today