zip4j icon indicating copy to clipboard operation
zip4j copied to clipboard

Adding comments to an existing zip64 file can corrupt the file

Open jptx1234 opened this issue 2 years ago • 0 comments

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)...

jptx1234 avatar Aug 02 '22 11:08 jptx1234