[Git][java-team/zip4j][master] 3 commits: New upstream version 2.6.1
Andrius Merkys
gitlab at salsa.debian.org
Wed Jun 10 11:52:25 BST 2020
Andrius Merkys pushed to branch master at Debian Java Maintainers / zip4j
Commits:
8ec2c583 by Andrius Merkys at 2020-06-10T06:26:54-04:00
New upstream version 2.6.1
- - - - -
713e3ef2 by Andrius Merkys at 2020-06-10T06:26:57-04:00
Update upstream source from tag 'upstream/2.6.1'
Update to upstream version '2.6.1'
with Debian dir 12618c94f9720a20769de8966df0065eda81c357
- - - - -
55793df5 by Andrius Merkys at 2020-06-10T06:28:17-04:00
Update changelog for 2.6.1-1 release
- - - - -
27 changed files:
- .travis.yml
- README.md
- debian/changelog
- pom.xml
- src/main/java/net/lingala/zip4j/ZipFile.java
- src/main/java/net/lingala/zip4j/headers/HeaderReader.java
- src/main/java/net/lingala/zip4j/headers/HeaderUtil.java
- src/main/java/net/lingala/zip4j/headers/HeaderWriter.java
- src/main/java/net/lingala/zip4j/io/inputstream/ZipInputStream.java
- src/main/java/net/lingala/zip4j/io/outputstream/CountingOutputStream.java
- + src/main/java/net/lingala/zip4j/io/outputstream/OutputStreamWithSplitZipSupport.java
- src/main/java/net/lingala/zip4j/io/outputstream/SplitOutputStream.java
- src/main/java/net/lingala/zip4j/model/ZipParameters.java
- src/main/java/net/lingala/zip4j/tasks/AbstractAddFileToZipTask.java
- src/main/java/net/lingala/zip4j/tasks/RemoveFilesFromZipTask.java
- src/main/java/net/lingala/zip4j/util/FileUtils.java
- src/test/java/net/lingala/zip4j/CreateZipFileIT.java
- src/test/java/net/lingala/zip4j/ExtractZipFileIT.java
- src/test/java/net/lingala/zip4j/ZipFileZip64IT.java
- src/test/java/net/lingala/zip4j/headers/HeaderUtilTest.java
- src/test/java/net/lingala/zip4j/io/inputstream/ZipInputStreamIT.java
- src/test/java/net/lingala/zip4j/testutils/TestUtils.java
- src/test/java/net/lingala/zip4j/util/FileUtilsIT.java
- src/test/java/net/lingala/zip4j/util/FileUtilsTestLinuxAndMac.java
- src/test/java/net/lingala/zip4j/util/FileUtilsTestWindows.java
- + src/test/resources/test-archives/jar-dir-fh-entry-size-2.jar
- + src/test/resources/test-archives/jar-dir-lfh-and-fh-entry-size-2.jar
Changes:
=====================================
.travis.yml
=====================================
@@ -4,4 +4,4 @@ before_script:
- 'if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then bash trigger-android-build.sh ${CIRCLE_CI_TOKEN} || travis_terminate 1; fi'
script:
- - travis_wait 30 mvn clean verify
+ - travis_wait 45 mvn clean verify
=====================================
README.md
=====================================
@@ -62,7 +62,7 @@ once again, and makes me support Zip4j as much as I can..
<dependency>
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
- <version>2.6.0</version>
+ <version>2.6.1</version>
</dependency>
~~~~
@@ -514,8 +514,8 @@ public class ZipInputStreamExample {
int readLen;
byte[] readBuffer = new byte[4096];
- try (FileInputStream fileInputStream = new FileInputStream(zipFile);
- ZipInputStream zipInputStream = new ZipInputStream(fileInputStream, password)) {
+ InputStream inputStream = new FileInputStream(zipFile);
+ try (ZipInputStream zipInputStream = new ZipInputStream(inputStream, password)) {
while ((localFileHeader = zipInputStream.getNextEntry()) != null) {
File extractedFile = new File(localFileHeader.getFileName());
try (OutputStream outputStream = new FileOutputStream(extractedFile)) {
@@ -544,15 +544,23 @@ ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
ProgressMonitor progressMonitor = zipFile.getProgressMonitor();
zipFile.setRunInThread(true);
-zipFile.addFolder("/some/folder");
+zipFile.addFolder(new File("/some/folder"));
while (!progressMonitor.getState().equals(ProgressMonitor.State.READY)) {
System.out.println("Percentage done: " + progressMonitor.getPercentDone());
System.out.println("Current file: " + progressMonitor.getFileName());
System.out.println("Current task: " + progressMonitor.getCurrentTask());
-
+
Thread.sleep(100);
}
+
+if (progressMonitor.getResult().equals(ProgressMonitor.Result.SUCCESS)) {
+ System.out.println("Successfully added folder to zip");
+} else if (progressMonitor.getResult().equals(ProgressMonitor.Result.ERROR)) {
+ System.out.println("Error occurred. Error message: " + progressMonitor.getException().getMessage());
+} else if (progressMonitor.getResult().equals(ProgressMonitor.Result.CANCELLED)) {
+ System.out.println("Task cancelled");
+}
~~~
Note that in the above example, `addFolder()` will almost immediately return back the control to the caller. The client
=====================================
debian/changelog
=====================================
@@ -1,3 +1,9 @@
+zip4j (2.6.1-1) unstable; urgency=medium
+
+ * New upstream version 2.6.1
+
+ -- Andrius Merkys <merkys at debian.org> Wed, 10 Jun 2020 06:28:11 -0400
+
zip4j (2.6.0-1) unstable; urgency=medium
* New upstream version 2.6.0
=====================================
pom.xml
=====================================
@@ -6,7 +6,7 @@
<groupId>net.lingala.zip4j</groupId>
<artifactId>zip4j</artifactId>
- <version>2.6.1-SNAPSHOT</version>
+ <version>2.6.2-SNAPSHOT</version>
<name>Zip4j</name>
<description>Zip4j - A Java library for zip files and streams</description>
=====================================
src/main/java/net/lingala/zip4j/ZipFile.java
=====================================
@@ -62,7 +62,6 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
-import static net.lingala.zip4j.util.FileUtils.assertFilesExist;
import static net.lingala.zip4j.util.FileUtils.isNumberedSplitFile;
import static net.lingala.zip4j.util.InternalZipConstants.CHARSET_UTF_8;
import static net.lingala.zip4j.util.UnzipUtil.createZipInputStream;
@@ -289,8 +288,6 @@ public class ZipFile {
throw new ZipException("invalid operation - Zip4j is in busy state");
}
- assertFilesExist(filesToAdd);
-
readZipInfo();
if (zipModel == null) {
=====================================
src/main/java/net/lingala/zip4j/headers/HeaderReader.java
=====================================
@@ -138,16 +138,9 @@ public class HeaderReader {
CentralDirectory centralDirectory = new CentralDirectory();
List<FileHeader> fileHeaders = new ArrayList<>();
- long offSetStartCentralDir = getOffsetCentralDirectory(zipModel);
+ long offSetStartCentralDir = HeaderUtil.getOffsetStartOfCentralDirectory(zipModel);
long centralDirEntryCount = getNumberOfEntriesInCentralDirectory(zipModel);
-
- if (zipModel.isZip64Format()) {
- offSetStartCentralDir = zipModel.getZip64EndOfCentralDirectoryRecord()
- .getOffsetStartCentralDirectoryWRTStartDiskNumber();
- centralDirEntryCount = (int) zipModel.getZip64EndOfCentralDirectoryRecord()
- .getTotalNumberOfEntriesInCentralDirectory();
- }
-
+
zip4jRaf.seek(offSetStartCentralDir);
byte[] shortBuff = new byte[2];
@@ -701,14 +694,6 @@ public class HeaderReader {
return null;
}
- private long getOffsetCentralDirectory(ZipModel zipModel) {
- if (zipModel.isZip64Format()) {
- return zipModel.getZip64EndOfCentralDirectoryRecord().getOffsetStartCentralDirectoryWRTStartDiskNumber();
- }
-
- return zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory();
- }
-
private long getNumberOfEntriesInCentralDirectory(ZipModel zipModel) {
if (zipModel.isZip64Format()) {
return zipModel.getZip64EndOfCentralDirectoryRecord().getTotalNumberOfEntriesInCentralDirectory();
=====================================
src/main/java/net/lingala/zip4j/headers/HeaderUtil.java
=====================================
@@ -87,12 +87,20 @@ public class HeaderUtil {
List<FileHeader> fileHeaders = zipModel.getCentralDirectory().getFileHeaders();
if (indexOfFileHeader == fileHeaders.size() - 1) {
- return getOffsetOfEndOfCentralDirectory(zipModel);
+ return getOffsetStartOfCentralDirectory(zipModel);
} else {
return fileHeaders.get(indexOfFileHeader + 1).getOffsetLocalHeader();
}
}
+ public static long getOffsetStartOfCentralDirectory(ZipModel zipModel) {
+ if (zipModel.isZip64Format()) {
+ return zipModel.getZip64EndOfCentralDirectoryRecord().getOffsetStartCentralDirectoryWRTStartDiskNumber();
+ }
+
+ return zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory();
+ }
+
public static List<FileHeader> getFileHeadersUnderDirectory(List<FileHeader> allFileHeaders, FileHeader rootFileHeader) {
if (!rootFileHeader.isDirectory()) {
return Collections.emptyList();
@@ -114,14 +122,6 @@ public class HeaderUtil {
return totalUncompressedSize;
}
- private static long getOffsetOfEndOfCentralDirectory(ZipModel zipModel) {
- if (zipModel.isZip64Format()) {
- return zipModel.getZip64EndOfCentralDirectoryRecord().getOffsetStartCentralDirectoryWRTStartDiskNumber();
- }
-
- return zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory();
- }
-
private static FileHeader getFileHeaderWithExactMatch(ZipModel zipModel, String fileName) throws ZipException {
if (zipModel == null) {
throw new ZipException("zip model is null, cannot determine file header with exact match for fileName: "
=====================================
src/main/java/net/lingala/zip4j/headers/HeaderWriter.java
=====================================
@@ -18,6 +18,7 @@ package net.lingala.zip4j.headers;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.io.outputstream.CountingOutputStream;
+import net.lingala.zip4j.io.outputstream.OutputStreamWithSplitZipSupport;
import net.lingala.zip4j.io.outputstream.SplitOutputStream;
import net.lingala.zip4j.model.AESExtraDataRecord;
import net.lingala.zip4j.model.ExtraDataRecord;
@@ -348,10 +349,10 @@ public class HeaderWriter {
private void processHeaderData(ZipModel zipModel, OutputStream outputStream) throws IOException {
int currentSplitFileCounter = 0;
- if (outputStream instanceof CountingOutputStream) {
+ if (outputStream instanceof OutputStreamWithSplitZipSupport) {
zipModel.getEndOfCentralDirectoryRecord().setOffsetOfStartOfCentralDirectory(
- ((CountingOutputStream) outputStream).getFilePointer());
- currentSplitFileCounter = ((CountingOutputStream) outputStream).getCurrentSplitFileCounter();
+ ((OutputStreamWithSplitZipSupport) outputStream).getFilePointer());
+ currentSplitFileCounter = ((OutputStreamWithSplitZipSupport) outputStream).getCurrentSplitFileCounter();
}
if (zipModel.isZip64Format()) {
@@ -362,6 +363,8 @@ public class HeaderWriter {
zipModel.setZip64EndOfCentralDirectoryLocator(new Zip64EndOfCentralDirectoryLocator());
}
+ zipModel.getZip64EndOfCentralDirectoryRecord().setOffsetStartCentralDirectoryWRTStartDiskNumber(
+ zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory());
zipModel.getZip64EndOfCentralDirectoryLocator().setNumberOfDiskStartOfZip64EndOfCentralDirectoryRecord(
currentSplitFileCounter);
zipModel.getZip64EndOfCentralDirectoryLocator().setTotalNumberOfDiscs(currentSplitFileCounter + 1);
=====================================
src/main/java/net/lingala/zip4j/io/inputstream/ZipInputStream.java
=====================================
@@ -300,9 +300,14 @@ public class ZipInputStream extends InputStream {
}
private void readUntilEndOfEntry() throws IOException {
+ if (localFileHeader.isDirectory() || localFileHeader.getCompressedSize() == 0) {
+ return;
+ }
+
if (endOfEntryBuffer == null) {
endOfEntryBuffer = new byte[512];
}
+
while (read(endOfEntryBuffer) != -1);
}
=====================================
src/main/java/net/lingala/zip4j/io/outputstream/CountingOutputStream.java
=====================================
@@ -5,7 +5,7 @@ import net.lingala.zip4j.exception.ZipException;
import java.io.IOException;
import java.io.OutputStream;
-public class CountingOutputStream extends OutputStream {
+public class CountingOutputStream extends OutputStream implements OutputStreamWithSplitZipSupport {
private OutputStream outputStream;
private long numberOfBytesWritten = 0;
@@ -30,6 +30,7 @@ public class CountingOutputStream extends OutputStream {
numberOfBytesWritten += len;
}
+ @Override
public int getCurrentSplitFileCounter() {
if (isSplitZipFile()) {
return ((SplitOutputStream) outputStream).getCurrentSplitFileCounter();
@@ -75,6 +76,7 @@ public class CountingOutputStream extends OutputStream {
return ((SplitOutputStream)outputStream).checkBufferSizeAndStartNextSplitFile(bufferSize);
}
+ @Override
public long getFilePointer() throws IOException {
if (outputStream instanceof SplitOutputStream) {
return ((SplitOutputStream) outputStream).getFilePointer();
=====================================
src/main/java/net/lingala/zip4j/io/outputstream/OutputStreamWithSplitZipSupport.java
=====================================
@@ -0,0 +1,10 @@
+package net.lingala.zip4j.io.outputstream;
+
+import java.io.IOException;
+
+public interface OutputStreamWithSplitZipSupport {
+
+ long getFilePointer() throws IOException;
+
+ int getCurrentSplitFileCounter();
+}
=====================================
src/main/java/net/lingala/zip4j/io/outputstream/SplitOutputStream.java
=====================================
@@ -30,7 +30,7 @@ import java.io.RandomAccessFile;
import static net.lingala.zip4j.util.FileUtils.getZipFileNameWithoutExtension;
import static net.lingala.zip4j.util.InternalZipConstants.MIN_SPLIT_LENGTH;
-public class SplitOutputStream extends OutputStream {
+public class SplitOutputStream extends OutputStream implements OutputStreamWithSplitZipSupport {
private RandomAccessFile raf;
private long splitLength;
@@ -192,6 +192,7 @@ public class SplitOutputStream extends OutputStream {
raf.close();
}
+ @Override
public long getFilePointer() throws IOException {
return raf.getFilePointer();
}
@@ -204,6 +205,7 @@ public class SplitOutputStream extends OutputStream {
return splitLength;
}
+ @Override
public int getCurrentSplitFileCounter() {
return currSplitFileCounter;
}
=====================================
src/main/java/net/lingala/zip4j/model/ZipParameters.java
=====================================
@@ -101,6 +101,8 @@ public class ZipParameters {
this.rootFolderNameInZip = zipParameters.getRootFolderNameInZip();
this.fileComment = zipParameters.getFileComment();
this.symbolicLinkAction = zipParameters.getSymbolicLinkAction();
+ this.excludeFileFilter = zipParameters.getExcludeFileFilter();
+ this.unixMode = zipParameters.isUnixMode();
}
/**
=====================================
src/main/java/net/lingala/zip4j/tasks/AbstractAddFileToZipTask.java
=====================================
@@ -1,6 +1,7 @@
package net.lingala.zip4j.tasks;
import net.lingala.zip4j.exception.ZipException;
+import net.lingala.zip4j.headers.HeaderUtil;
import net.lingala.zip4j.headers.HeaderWriter;
import net.lingala.zip4j.io.outputstream.SplitOutputStream;
import net.lingala.zip4j.io.outputstream.ZipOutputStream;
@@ -36,6 +37,7 @@ import static net.lingala.zip4j.progress.ProgressMonitor.Task.ADD_ENTRY;
import static net.lingala.zip4j.progress.ProgressMonitor.Task.CALCULATE_CRC;
import static net.lingala.zip4j.progress.ProgressMonitor.Task.REMOVE_ENTRY;
import static net.lingala.zip4j.util.CrcUtil.computeFileCrc;
+import static net.lingala.zip4j.util.FileUtils.assertFilesExist;
import static net.lingala.zip4j.util.FileUtils.getRelativeFileName;
import static net.lingala.zip4j.util.InternalZipConstants.BUFF_SIZE;
import static net.lingala.zip4j.util.Zip4jUtil.javaToDosTime;
@@ -59,12 +61,13 @@ public abstract class AbstractAddFileToZipTask<T> extends AsyncZipTask<T> {
void addFilesToZip(List<File> filesToAdd, ProgressMonitor progressMonitor, ZipParameters zipParameters, Charset charset)
throws IOException {
+ assertFilesExist(filesToAdd, zipParameters.getSymbolicLinkAction());
+
List<File> updatedFilesToAdd = removeFilesIfExists(filesToAdd, zipParameters, progressMonitor, charset);
try (SplitOutputStream splitOutputStream = new SplitOutputStream(zipModel.getZipFile(), zipModel.getSplitLength());
ZipOutputStream zipOutputStream = initializeOutputStream(splitOutputStream, charset)) {
-
for (File fileToAdd : updatedFilesToAdd) {
verifyIfTaskIsCancelled();
ZipParameters clonedZipParameters = cloneAndAdjustZipParameters(zipParameters, fileToAdd, progressMonitor);
@@ -95,7 +98,7 @@ public abstract class AbstractAddFileToZipTask<T> extends AsyncZipTask<T> {
zipOutputStream.putNextEntry(clonedZipParameters);
- String symLinkTarget = fileToAdd.toPath().toRealPath().toString();
+ String symLinkTarget = FileUtils.readSymbolicLink(fileToAdd);
zipOutputStream.write(symLinkTarget.getBytes());
closeEntry(zipOutputStream, splitOutputStream, fileToAdd, true);
@@ -162,10 +165,7 @@ public abstract class AbstractAddFileToZipTask<T> extends AsyncZipTask<T> {
ZipOutputStream initializeOutputStream(SplitOutputStream splitOutputStream, Charset charset) throws IOException {
if (zipModel.getZipFile().exists()) {
- if (zipModel.getEndOfCentralDirectoryRecord() == null) {
- throw new ZipException("invalid end of central directory record");
- }
- splitOutputStream.seek(zipModel.getEndOfCentralDirectoryRecord().getOffsetOfStartOfCentralDirectory());
+ splitOutputStream.seek(HeaderUtil.getOffsetStartOfCentralDirectory(zipModel));
}
return new ZipOutputStream(splitOutputStream, password, charset, zipModel);
=====================================
src/main/java/net/lingala/zip4j/tasks/RemoveFilesFromZipTask.java
=====================================
@@ -103,7 +103,7 @@ public class RemoveFilesFromZipTask extends AbstractModifyFileTask<RemoveFilesFr
}
private void updateHeaders(FileHeader fileHeaderThatWasRemoved, long offsetToSubtract) throws ZipException {
- updateOffsetsForAllSubsequentFileHeaders(zipModel, fileHeaderThatWasRemoved, Math.negateExact(offsetToSubtract));
+ updateOffsetsForAllSubsequentFileHeaders(zipModel, fileHeaderThatWasRemoved, negate(offsetToSubtract));
EndOfCentralDirectoryRecord endOfCentralDirectoryRecord = zipModel.getEndOfCentralDirectoryRecord();
endOfCentralDirectoryRecord.setOffsetOfStartOfCentralDirectory(
@@ -128,6 +128,14 @@ public class RemoveFilesFromZipTask extends AbstractModifyFileTask<RemoveFilesFr
}
}
+ private long negate(long val) {
+ if (val == Long.MIN_VALUE) {
+ throw new ArithmeticException("long overflow");
+ }
+
+ return -val;
+ }
+
@Override
protected ProgressMonitor.Task getTask() {
return ProgressMonitor.Task.REMOVE_ENTRY;
=====================================
src/main/java/net/lingala/zip4j/util/FileUtils.java
=====================================
@@ -11,6 +11,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.file.Files;
+import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.attribute.DosFileAttributeView;
import java.nio.file.attribute.DosFileAttributes;
@@ -71,7 +72,7 @@ public class FileUtils {
public static byte[] getFileAttributes(File file) {
try {
- if (file == null || !file.exists()) {
+ if (file == null || (!Files.isSymbolicLink(file.toPath()) && !file.exists())) {
return new byte[4];
}
@@ -269,7 +270,7 @@ public class FileUtils {
}
if (isSymbolicLink(fileToAdd)) {
- return fileToAdd.toPath().toRealPath().getFileName().toString();
+ return fileToAdd.toPath().toRealPath(LinkOption.NOFOLLOW_LINKS).getFileName().toString();
}
return fileToAdd.getName();
@@ -327,10 +328,17 @@ public class FileUtils {
}
}
- public static void assertFilesExist(List<File> files) throws ZipException {
+ public static void assertFilesExist(List<File> files, ZipParameters.SymbolicLinkAction symLinkAction) throws ZipException {
for (File file : files) {
- if (!file.exists()) {
- throw new ZipException("File does not exist: " + file);
+ if (isSymbolicLink(file)) {
+ // If symlink is INCLUDE_LINK_ONLY, and if the above condition is true, it means that the link exists and there
+ // will be no need to check for link existence explicitly, check only for target file existence if required
+ if (symLinkAction.equals(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_AND_LINKED_FILE)
+ || symLinkAction.equals(ZipParameters.SymbolicLinkAction.INCLUDE_LINKED_FILE_ONLY)) {
+ assertSymbolicLinkTargetExists(file);
+ }
+ } else {
+ assertFileExists(file);
}
}
}
@@ -380,6 +388,14 @@ public class FileUtils {
}
}
+ public static String readSymbolicLink(File file) {
+ try {
+ return Files.readSymbolicLink(file.toPath()).toString();
+ } catch (Exception | Error e) {
+ return "";
+ }
+ }
+
private static String getExtensionZerosPrefix(int index) {
if (index < 9) {
return "00";
@@ -396,7 +412,7 @@ public class FileUtils {
return;
}
- DosFileAttributeView fileAttributeView = Files.getFileAttributeView(file, DosFileAttributeView.class);
+ DosFileAttributeView fileAttributeView = Files.getFileAttributeView(file, DosFileAttributeView.class, LinkOption.NOFOLLOW_LINKS);
try {
fileAttributeView.setReadOnly(isBitSet(fileAttributes[0], 0));
fileAttributeView.setHidden(isBitSet(fileAttributes[0], 1));
@@ -434,7 +450,8 @@ public class FileUtils {
byte[] fileAttributes = new byte[4];
try {
- DosFileAttributeView dosFileAttributeView = Files.getFileAttributeView(file, DosFileAttributeView.class);
+ DosFileAttributeView dosFileAttributeView = Files.getFileAttributeView(file, DosFileAttributeView.class,
+ LinkOption.NOFOLLOW_LINKS);
DosFileAttributes dosFileAttributes = dosFileAttributeView.readAttributes();
byte windowsAttribute = 0;
@@ -451,11 +468,24 @@ public class FileUtils {
return fileAttributes;
}
+ private static void assertFileExists(File file) throws ZipException {
+ if (!file.exists()) {
+ throw new ZipException("File does not exist: " + file);
+ }
+ }
+
+ private static void assertSymbolicLinkTargetExists(File file) throws ZipException {
+ if (!file.exists()) {
+ throw new ZipException("Symlink target '" + readSymbolicLink(file) + "' does not exist for link '" + file + "'");
+ }
+ }
+
private static byte[] getPosixFileAttributes(Path file) {
byte[] fileAttributes = new byte[4];
try {
- PosixFileAttributeView posixFileAttributeView = Files.getFileAttributeView(file, PosixFileAttributeView.class);
+ PosixFileAttributeView posixFileAttributeView = Files.getFileAttributeView(file, PosixFileAttributeView.class,
+ LinkOption.NOFOLLOW_LINKS);
Set<PosixFilePermission> posixFilePermissions = posixFileAttributeView.readAttributes().permissions();
fileAttributes[3] = setBitIfApplicable(Files.isRegularFile(file), fileAttributes[3], 7);
=====================================
src/test/java/net/lingala/zip4j/CreateZipFileIT.java
=====================================
@@ -426,6 +426,76 @@ public class CreateZipFileIT extends AbstractIT {
"sub-folder2/symlink.link");
}
+ @Test
+ public void testAddSymlinkWithLinkOnlyMissingTarget() throws IOException {
+ File targetFile = Paths.get(temporaryFolder.getRoot().getAbsolutePath(), "foo").toFile();
+ File symlink = createSymlink(targetFile, temporaryFolder.getRoot());
+ ZipFile zipFile = new ZipFile(generatedZipFile);
+ ZipParameters zipParameters = new ZipParameters();
+ zipParameters.setSymbolicLinkAction(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_ONLY);
+
+ zipFile.addFile(symlink, zipParameters);
+
+ assertThat(zipFile.getFileHeaders()).hasSize(1);
+ assertThat(zipFile.getFileHeaders().get(0).getFileName()).isEqualTo(symlink.getName());
+ verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 1, false);
+ verifyGeneratedSymlink(symlink, targetFile);
+ }
+
+ @Test
+ public void testAddSymlinkWithLinkedFileOnlyMissingTargetThrowsException() throws IOException {
+ testAddSymlinkThrowsExceptionForMissingTarget(ZipParameters.SymbolicLinkAction.INCLUDE_LINKED_FILE_ONLY);
+ }
+
+ @Test
+ public void testAddSymlinkWithLinkAndLinkedFileMissingTargetThrowsException() throws IOException {
+ testAddSymlinkThrowsExceptionForMissingTarget(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_AND_LINKED_FILE);
+ }
+
+ @Test
+ public void testAddSymlinksInAFolderWithLinkOnlyMissingTarget() throws IOException {
+ Path testFolderPath = temporaryFolder.newFolder("test-folder").toPath();
+ Path subFolder1 = Files.createDirectory(Paths.get(testFolderPath.toString(), "sub-folder1"));
+ Path subFolder2 = Files.createDirectory(Paths.get(testFolderPath.toString(), "sub-folder2"));
+
+ File targetFile = Paths.get(temporaryFolder.getRoot().getAbsolutePath(), "foo").toFile();
+
+ createSymlink(targetFile, testFolderPath.toFile());
+ createSymlink(getTestFileFromResources("file_PDF_1MB.pdf"), subFolder1.toFile());
+ createSymlink(getTestFileFromResources("sample_text_large.txt"), subFolder2.toFile());
+
+ File testFolder = testFolderPath.toFile();
+
+ ZipFile zipFile = new ZipFile(generatedZipFile);
+ ZipParameters zipParameters = new ZipParameters();
+ zipParameters.setSymbolicLinkAction(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_ONLY);
+
+ zipFile.addFolder(testFolder, zipParameters);
+
+ verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 6, false);
+ verifyFileNamesInZip(zipFile,
+ "test-folder/",
+ "test-folder/symlink.link",
+ "test-folder/sub-folder1/",
+ "test-folder/sub-folder1/symlink.link",
+ "test-folder/sub-folder2/",
+ "test-folder/sub-folder2/symlink.link");
+ }
+
+ private void testAddSymlinkThrowsExceptionForMissingTarget(ZipParameters.SymbolicLinkAction symbolicLinkAction)
+ throws IOException {
+ File targetFile = Paths.get(temporaryFolder.getRoot().getAbsolutePath(), "foo").toFile();
+ File symlink = createSymlink(targetFile, temporaryFolder.getRoot());
+ ZipFile zipFile = new ZipFile(generatedZipFile);
+ ZipParameters zipParameters = new ZipParameters();
+ zipParameters.setSymbolicLinkAction(symbolicLinkAction);
+
+ expectedException.expect(ZipException.class);
+ expectedException.expectMessage("Symlink target '" + targetFile + "' does not exist for link '" + symlink + "'");
+
+ zipFile.addFile(symlink, zipParameters);
+ }
+
private void testCreateZipFileWithFileEntryComment(String fileCommentPrefix, Charset charset) throws IOException {
ZipParameters zipParameters = new ZipParameters();
ZipFile zipFile = initializeZipFileWithCharset(charset);
=====================================
src/test/java/net/lingala/zip4j/ExtractZipFileIT.java
=====================================
@@ -475,6 +475,16 @@ public class ExtractZipFileIT extends AbstractIT {
ZipFileVerifier.verifyFileContent(TestUtils.getTestFileFromResources("öüäöäö/asöäööl"), outputFile);
}
+ @Test
+ public void testExtractJarFileWithFileHeaderCompressedSize2() throws IOException {
+ extractFile(TestUtils.getTestArchiveFromResources("jar-dir-fh-entry-size-2.jar"));
+ }
+
+ @Test
+ public void testExtractJarFileWithOnlyFileAndLocalFileHeaderCompressedSize2() throws IOException {
+ extractFile(TestUtils.getTestArchiveFromResources("jar-dir-lfh-and-fh-entry-size-2.jar"));
+ }
+
private void addFileToZip(ZipFile zipFile, String fileName, EncryptionMethod encryptionMethod, String password) throws ZipException {
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(encryptionMethod != null);
@@ -550,7 +560,9 @@ public class ExtractZipFileIT extends AbstractIT {
return file.get();
}
- private File createZipFileAndSplit(List<File> filesToAddToZip, long splitLength, boolean encrypt, EncryptionMethod encryptionMethod) throws IOException {
+ private File createZipFileAndSplit(List<File> filesToAddToZip, long splitLength, boolean encrypt,
+ EncryptionMethod encryptionMethod) throws IOException {
+
ZipFile zipFile = new ZipFile(generatedZipFile, PASSWORD);
ZipParameters zipParameters = new ZipParameters();
zipParameters.setEncryptFiles(encrypt);
@@ -560,4 +572,8 @@ public class ExtractZipFileIT extends AbstractIT {
return TestUtils.splitFileWith7ZipFormat(zipFile.getFile(), temporaryFolder.getRoot(), splitLength);
}
+ private void extractFile(File fileToExtract) throws IOException {
+ ZipFile zipFile = new ZipFile(fileToExtract);
+ zipFile.extractAll(outputFolder.getPath());
+ }
}
=====================================
src/test/java/net/lingala/zip4j/ZipFileZip64IT.java
=====================================
@@ -9,11 +9,13 @@ import net.lingala.zip4j.model.enums.RandomAccessFileMode;
import net.lingala.zip4j.testutils.HeaderVerifier;
import net.lingala.zip4j.testutils.RandomInputStream;
import net.lingala.zip4j.testutils.SlowTests;
+import net.lingala.zip4j.testutils.TestUtils;
import net.lingala.zip4j.testutils.ZipFileVerifier;
import net.lingala.zip4j.util.InternalZipConstants;
import org.junit.Test;
import org.junit.experimental.categories.Category;
+import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -135,6 +137,20 @@ public class ZipFileZip64IT extends AbstractIT {
HeaderVerifier.verifyFileHeadersDoesNotExist(zipFile, filesToRemove);
}
+ @Test
+ public void testZip64WhenAddingFilesWithNewlyInstantiatedZipFile() throws IOException {
+ File testFileToAdd = TestUtils.generateFileOfSize(temporaryFolder, 1073741824); // 1 GB
+ ZipParameters zipParameters = new ZipParameters();
+ zipParameters.setCompressionMethod(CompressionMethod.STORE);
+
+ for (int i = 0; i < 6; i++) {
+ zipParameters.setFileNameInZip(Integer.toString(i));
+ new ZipFile(generatedZipFile).addFile(testFileToAdd, zipParameters);
+ }
+
+ ZipFileVerifier.verifyZipFileByExtractingAllFiles(generatedZipFile, null, outputFolder, 6, false);
+ }
+
private void verifyZip64HeadersPresent() throws IOException {
HeaderReader headerReader = new HeaderReader();
ZipModel zipModel = headerReader.readAllHeaders(new RandomAccessFile(generatedZipFile,
=====================================
src/test/java/net/lingala/zip4j/headers/HeaderUtilTest.java
=====================================
@@ -2,7 +2,9 @@ package net.lingala.zip4j.headers;
import net.lingala.zip4j.exception.ZipException;
import net.lingala.zip4j.model.CentralDirectory;
+import net.lingala.zip4j.model.EndOfCentralDirectoryRecord;
import net.lingala.zip4j.model.FileHeader;
+import net.lingala.zip4j.model.Zip64EndOfCentralDirectoryRecord;
import net.lingala.zip4j.model.Zip64ExtendedInfo;
import net.lingala.zip4j.model.ZipModel;
import net.lingala.zip4j.util.InternalZipConstants;
@@ -308,6 +310,30 @@ public class HeaderUtilTest {
assertThat(HeaderUtil.getTotalUncompressedSizeOfAllFileHeaders(fileHeaders)).isEqualTo(6000);
}
+ @Test
+ public void testGetOffsetStartOfCentralDirectoryForZip64Format() {
+ long offsetCentralDirectory = InternalZipConstants.ZIP_64_SIZE_LIMIT + 100;
+ ZipModel zipModel = new ZipModel();
+ zipModel.setZip64Format(true);
+ Zip64EndOfCentralDirectoryRecord zip64EndOfCentralDirectoryRecord = new Zip64EndOfCentralDirectoryRecord();
+ zip64EndOfCentralDirectoryRecord.setOffsetStartCentralDirectoryWRTStartDiskNumber(offsetCentralDirectory);
+ zipModel.setZip64EndOfCentralDirectoryRecord(zip64EndOfCentralDirectoryRecord);
+
+ assertThat(HeaderUtil.getOffsetStartOfCentralDirectory(zipModel)).isEqualTo(offsetCentralDirectory);
+ }
+
+ @Test
+ public void testGetOffsetStartOfCentralDirectoryForNonZip64Format() {
+ long offsetStartOfCentralDirectory = InternalZipConstants.ZIP_64_SIZE_LIMIT - 100;
+ ZipModel zipModel = new ZipModel();
+ zipModel.setZip64Format(false);
+ EndOfCentralDirectoryRecord endOfCentralDirectoryRecord = new EndOfCentralDirectoryRecord();
+ endOfCentralDirectoryRecord.setOffsetOfStartOfCentralDirectory(offsetStartOfCentralDirectory);
+ zipModel.setEndOfCentralDirectoryRecord(endOfCentralDirectoryRecord);
+
+ assertThat(HeaderUtil.getOffsetStartOfCentralDirectory(zipModel)).isEqualTo(offsetStartOfCentralDirectory);
+ }
+
private List<FileHeader> generateFileHeaderWithFileNamesWithEmptyAndNullFileNames(String fileNamePrefix, int numberOfEntriesToAdd) {
List<FileHeader> fileHeaders = generateFileHeaderWithFileNames(fileNamePrefix, numberOfEntriesToAdd);
fileHeaders.add(generateFileHeader(""));
=====================================
src/test/java/net/lingala/zip4j/io/inputstream/ZipInputStreamIT.java
=====================================
@@ -188,6 +188,17 @@ public class ZipInputStreamIT extends AbstractIT {
assertThat(filenameSet.contains(expactedFileName)).isTrue();
}
+ @Test
+ public void testExtractJarFile() throws IOException {
+ byte[] b = new byte[4096];
+ File jarFile = getTestArchiveFromResources("jar-dir-fh-entry-size-2.jar");
+ try (ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(jarFile))) {
+ while (zipInputStream.getNextEntry() != null) {
+ zipInputStream.read(b);
+ }
+ }
+ }
+
private void extractZipFileWithInputStreams(File zipFile, char[] password) throws IOException {
extractZipFileWithInputStreams(zipFile, password, 4096, AesVersion.TWO);
}
=====================================
src/test/java/net/lingala/zip4j/testutils/TestUtils.java
=====================================
@@ -4,6 +4,7 @@ import net.lingala.zip4j.io.outputstream.ZipOutputStream;
import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.util.FileUtils;
import net.lingala.zip4j.util.InternalZipConstants;
+import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.FileInputStream;
@@ -14,8 +15,9 @@ import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.file.Files;
-import java.util.List;
import java.nio.file.Paths;
+import java.util.List;
+import java.util.Random;
public class TestUtils {
@@ -110,6 +112,25 @@ public class TestUtils {
}
}
+ public static File generateFileOfSize(TemporaryFolder temporaryFolder, long fileSize) throws IOException {
+ File outputFile = temporaryFolder.newFile();
+ byte[] b = new byte[8 * InternalZipConstants.BUFF_SIZE];
+ Random random = new Random();
+ long bytesWritten = 0;
+ int bufferWriteLength;
+
+ try (OutputStream outputStream = new FileOutputStream(outputFile)) {
+ while (bytesWritten < fileSize) {
+ random.nextBytes(b);
+ bufferWriteLength = bytesWritten + b.length > fileSize ? ((int) (fileSize - bytesWritten)) : b.length;
+ outputStream.write(b, 0, bufferWriteLength);
+ bytesWritten += bufferWriteLength;
+ }
+ }
+
+ return outputFile;
+ }
+
private static OutputStream startNext7ZipSplitStream(File sourceFile, File outputFolder, int index) throws IOException {
File outputFile = getFileNameFor7ZipSplitIndex(sourceFile, outputFolder, index);
return new FileOutputStream(outputFile);
=====================================
src/test/java/net/lingala/zip4j/util/FileUtilsIT.java
=====================================
@@ -2,6 +2,7 @@ package net.lingala.zip4j.util;
import net.lingala.zip4j.AbstractIT;
import net.lingala.zip4j.exception.ZipException;
+import net.lingala.zip4j.model.ZipParameters;
import net.lingala.zip4j.model.enums.RandomAccessFileMode;
import net.lingala.zip4j.progress.ProgressMonitor;
import net.lingala.zip4j.testutils.TestUtils;
@@ -18,6 +19,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@@ -131,6 +133,60 @@ public class FileUtilsIT extends AbstractIT {
}
}
+ @Test
+ public void testAssertFilesExistWhenFileExistsDoesNotThrowException() throws IOException {
+ File newFile = temporaryFolder.newFile("new-file");
+ FileUtils.assertFilesExist(Collections.singletonList(newFile), ZipParameters.SymbolicLinkAction.INCLUDE_LINK_ONLY);
+ }
+
+ @Test
+ public void testAssertFilesExistWhenFileDoesNotExistThrowsException() throws IOException {
+ File newFile = Paths.get(temporaryFolder.getRoot().getPath(), "file-which-does-not-exist").toFile();
+ expectedException.expect(ZipException.class);
+ expectedException.expectMessage("File does not exist: " + newFile);
+
+ FileUtils.assertFilesExist(Collections.singletonList(newFile), ZipParameters.SymbolicLinkAction.INCLUDE_LINK_ONLY);
+ }
+
+ @Test
+ public void testAssertFilesExistForSymLinkWhenTargetDoesNotExistIncludeLinkOnlySuccess() throws IOException {
+ File targetFile = Paths.get(temporaryFolder.getRoot().getPath(), "file-which-does-not-exist").toFile();
+ File symlink = Paths.get(temporaryFolder.getRoot().getPath(), "symlink.link").toFile();
+ Files.createSymbolicLink(symlink.toPath(), targetFile.toPath());
+
+ FileUtils.assertFilesExist(Collections.singletonList(symlink), ZipParameters.SymbolicLinkAction.INCLUDE_LINK_ONLY);
+ }
+
+ @Test
+ public void testAssertFilesExistForSymLinkWhenTargetDoesNotExistIncludeLinkedFileOnlyThrowsException() throws IOException {
+ testAssertFileExistsForSymLinkWhenTargetDoesNotExist(ZipParameters.SymbolicLinkAction.INCLUDE_LINKED_FILE_ONLY);
+ }
+
+ @Test
+ public void testAssertFilesExistForSymLinkWhenTargetDoesNotExistIncludeLinkAndLinkedFileThrowsException() throws IOException {
+ testAssertFileExistsForSymLinkWhenTargetDoesNotExist(ZipParameters.SymbolicLinkAction.INCLUDE_LINK_AND_LINKED_FILE);
+ }
+
+ @Test
+ public void testReadSymbolicLink() throws IOException {
+ File targetFile = temporaryFolder.newFile("target-file");
+ File symlink = Paths.get(temporaryFolder.getRoot().getPath(), "symlink.link").toFile();
+ Files.createSymbolicLink(symlink.toPath(), targetFile.toPath());
+
+ assertThat(FileUtils.readSymbolicLink(symlink)).isEqualTo(targetFile.getPath());
+ }
+
+ private void testAssertFileExistsForSymLinkWhenTargetDoesNotExist(ZipParameters.SymbolicLinkAction symbolicLinkAction) throws IOException {
+ File targetFile = Paths.get(temporaryFolder.getRoot().getPath(), "file-which-does-not-exist").toFile();
+ File symlink = Paths.get(temporaryFolder.getRoot().getPath(), "symlink.link").toFile();
+ Files.createSymbolicLink(symlink.toPath(), targetFile.toPath());
+
+ expectedException.expect(ZipException.class);
+ expectedException.expectMessage("Symlink target '" + targetFile + "' does not exist for link '" + symlink + "'");
+
+ FileUtils.assertFilesExist(Collections.singletonList(symlink), symbolicLinkAction);
+ }
+
private void testInvalidOffsetsScenario(int start, int offset) throws IOException {
expectedException.expectMessage("invalid offsets");
expectedException.expect(ZipException.class);
=====================================
src/test/java/net/lingala/zip4j/util/FileUtilsTestLinuxAndMac.java
=====================================
@@ -148,14 +148,14 @@ public class FileUtilsTestLinuxAndMac {
);
}
- private PosixFileAttributeView mockPosixFileAttributeView(Path path, boolean isDirectory)
- throws IOException {
+ private PosixFileAttributeView mockPosixFileAttributeView(Path path, boolean isDirectory) throws IOException {
FileSystemProvider fileSystemProvider = mock(FileSystemProvider.class);
FileSystem fileSystem = mock(FileSystem.class);
PosixFileAttributeView posixFileAttributeView = mock(PosixFileAttributeView.class);
when(path.getFileSystem()).thenReturn(fileSystem);
- when(fileSystemProvider.getFileAttributeView(path, PosixFileAttributeView.class))
+ when(fileSystemProvider.getFileAttributeView(path, PosixFileAttributeView.class)).thenReturn(posixFileAttributeView);
+ when(fileSystemProvider.getFileAttributeView(path, PosixFileAttributeView.class, LinkOption.NOFOLLOW_LINKS))
.thenReturn(posixFileAttributeView);
when(path.getFileSystem().provider()).thenReturn(fileSystemProvider);
=====================================
src/test/java/net/lingala/zip4j/util/FileUtilsTestWindows.java
=====================================
@@ -7,7 +7,9 @@ import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.nio.file.FileSystem;
+import java.nio.file.LinkOption;
import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.DosFileAttributeView;
import java.nio.file.attribute.DosFileAttributes;
import java.nio.file.spi.FileSystemProvider;
@@ -47,7 +49,7 @@ public class FileUtilsTestWindows {
@Test
public void testSetFileAttributesOnWindowsMachineWhenAttributesSet() throws IOException {
Path mockedPath = mock(Path.class);
- DosFileAttributeView dosFileAttributeView = mockDosFileAttributeView(mockedPath, true);
+ DosFileAttributeView dosFileAttributeView = mockDosFileAttributeView(mockedPath, true, null);
byte attribute = 0;
attribute = BitUtils.setBit(attribute, 0);
@@ -66,7 +68,7 @@ public class FileUtilsTestWindows {
@Test
public void testSetFileAttributesOnWindowsWhenNoAttributesSetDoesNothing() throws IOException {
Path mockedPath = mock(Path.class);
- DosFileAttributeView dosFileAttributeView = mockDosFileAttributeView(mockedPath, true);
+ DosFileAttributeView dosFileAttributeView = mockDosFileAttributeView(mockedPath, true, null);
FileUtils.setFileAttributes(mockedPath, new byte[]{0, 0, 0, 0});
@@ -82,7 +84,11 @@ public class FileUtilsTestWindows {
@Test
public void testGetFileAttributesWhenFileDoesNotExistReturnsEmptyBytes() throws IOException {
File file = mock(File.class);
+ Path path = mock(Path.class);
+ when(file.toPath()).thenReturn(path);
when(file.exists()).thenReturn(false);
+ DosFileAttributes dosFileAttributes = mock(DosFileAttributes.class);
+ mockDosFileAttributeView(path, true, dosFileAttributes);
byte[] attributes = FileUtils.getFileAttributes(file);
@@ -100,8 +106,8 @@ public class FileUtilsTestWindows {
Path path = mock(Path.class);
when(file.toPath()).thenReturn(path);
when(file.exists()).thenReturn(true);
- DosFileAttributeView dosFileAttributeView = mockDosFileAttributeView(path, true);
DosFileAttributes dosFileAttributes = mock(DosFileAttributes.class);
+ DosFileAttributeView dosFileAttributeView = mockDosFileAttributeView(path, true, dosFileAttributes);
when(dosFileAttributeView.readAttributes()).thenReturn(dosFileAttributes);
when(dosFileAttributes.isReadOnly()).thenReturn(true);
when(dosFileAttributes.isHidden()).thenReturn(true);
@@ -116,13 +122,15 @@ public class FileUtilsTestWindows {
assertThat(isBitSet(attributes[0], 5)).isTrue();
}
- private DosFileAttributeView mockDosFileAttributeView(Path path, boolean fileExists) throws IOException {
+ private DosFileAttributeView mockDosFileAttributeView(Path path, boolean fileExists, DosFileAttributes dosFileAttributes) throws IOException {
FileSystemProvider fileSystemProvider = mock(FileSystemProvider.class);
FileSystem fileSystem = mock(FileSystem.class);
DosFileAttributeView dosFileAttributeView = mock(DosFileAttributeView.class);
+ when(fileSystemProvider.readAttributes(path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS)).thenReturn(dosFileAttributes);
when(path.getFileSystem()).thenReturn(fileSystem);
- when(fileSystemProvider.getFileAttributeView(path, DosFileAttributeView.class)).thenReturn(dosFileAttributeView);
+ when(fileSystemProvider.getFileAttributeView(path, DosFileAttributeView.class, LinkOption.NOFOLLOW_LINKS))
+ .thenReturn(dosFileAttributeView);
when(path.getFileSystem().provider()).thenReturn(fileSystemProvider);
if (!fileExists) {
=====================================
src/test/resources/test-archives/jar-dir-fh-entry-size-2.jar
=====================================
Binary files /dev/null and b/src/test/resources/test-archives/jar-dir-fh-entry-size-2.jar differ
=====================================
src/test/resources/test-archives/jar-dir-lfh-and-fh-entry-size-2.jar
=====================================
Binary files /dev/null and b/src/test/resources/test-archives/jar-dir-lfh-and-fh-entry-size-2.jar differ
View it on GitLab: https://salsa.debian.org/java-team/zip4j/-/compare/3c8dab5b0888d7e3145ca68a397c0818fe4017b9...55793df51848229d0b49d0edb0f752419521747c
--
View it on GitLab: https://salsa.debian.org/java-team/zip4j/-/compare/3c8dab5b0888d7e3145ca68a397c0818fe4017b9...55793df51848229d0b49d0edb0f752419521747c
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20200610/9236dc40/attachment.html>
More information about the pkg-java-commits
mailing list