Skip to content

Commit a28ca75

Browse files
#486 Set symlink as a file even if it points to directory
1 parent 7f74287 commit a28ca75

File tree

4 files changed

+37
-5
lines changed

4 files changed

+37
-5
lines changed

src/main/java/net/lingala/zip4j/tasks/AbstractExtractFileTask.java

+9-2
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,16 @@ protected void extractFile(ZipInputStream zipInputStream, FileHeader fileHeader,
5959
throw new ZipException("Could not create directory: " + outputFile);
6060
}
6161
}
62-
} else if (isSymbolicLink(fileHeader)) {
62+
} else if (isSymbolicLink) {
6363
createSymLink(zipInputStream, fileHeader, outputFile, progressMonitor);
6464
} else {
6565
checkOutputDirectoryStructure(outputFile);
6666
unzipFile(zipInputStream, outputFile, progressMonitor, readBuff);
6767
}
6868

69-
UnzipUtil.applyFileAttributes(fileHeader, outputFile);
69+
if (!isSymbolicLink) {
70+
UnzipUtil.applyFileAttributes(fileHeader, outputFile);
71+
}
7072
}
7173

7274
private void assertCanonicalPathsAreSame(File outputFile, String outputPath, FileHeader fileHeader)
@@ -128,6 +130,11 @@ private void createSymLink(ZipInputStream zipInputStream, FileHeader fileHeader,
128130

129131
try {
130132
Path linkTarget = Paths.get(symLinkPath);
133+
if (outputFile.exists()) {
134+
if (!outputFile.delete()) {
135+
throw new ZipException("Could not delete existing symlink " + outputFile);
136+
}
137+
}
131138
Files.createSymbolicLink(outputFile.toPath(), linkTarget);
132139
} catch (NoSuchMethodError error) {
133140
try (OutputStream outputStream = new FileOutputStream(outputFile)) {

src/main/java/net/lingala/zip4j/util/FileUtils.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -558,9 +558,17 @@ private static byte[] getPosixFileAttributes(Path file) {
558558
LinkOption.NOFOLLOW_LINKS);
559559
Set<PosixFilePermission> posixFilePermissions = posixFileAttributeView.readAttributes().permissions();
560560

561-
fileAttributes[3] = setBitIfApplicable(Files.isRegularFile(file), fileAttributes[3], 7);
562-
fileAttributes[3] = setBitIfApplicable(Files.isDirectory(file), fileAttributes[3], 6);
563-
fileAttributes[3] = setBitIfApplicable(Files.isSymbolicLink(file), fileAttributes[3], 5);
561+
boolean isSymlink = Files.isSymbolicLink(file);
562+
if (isSymlink) {
563+
// Mark as a regular file and not a directory if file is a symlink and even if the symlink points to a directory
564+
fileAttributes[3] = BitUtils.setBit(fileAttributes[3], 7);
565+
fileAttributes[3] = BitUtils.unsetBit(fileAttributes[3], 6);
566+
} else {
567+
fileAttributes[3] = setBitIfApplicable(Files.isRegularFile(file), fileAttributes[3], 7);
568+
fileAttributes[3] = setBitIfApplicable(Files.isDirectory(file), fileAttributes[3], 6);
569+
}
570+
571+
fileAttributes[3] = setBitIfApplicable(isSymlink, fileAttributes[3], 5);
564572
fileAttributes[3] = setBitIfApplicable(posixFilePermissions.contains(OWNER_READ), fileAttributes[3], 0);
565573
fileAttributes[2] = setBitIfApplicable(posixFilePermissions.contains(OWNER_WRITE), fileAttributes[2], 7);
566574
fileAttributes[2] = setBitIfApplicable(posixFilePermissions.contains(OWNER_EXECUTE), fileAttributes[2], 6);

src/test/java/net/lingala/zip4j/ExtractZipFileIT.java

+17
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.IOException;
2020
import java.io.InputStream;
2121
import java.nio.file.Files;
22+
import java.nio.file.Path;
2223
import java.nio.file.Paths;
2324
import java.util.ArrayList;
2425
import java.util.Arrays;
@@ -328,6 +329,22 @@ public void testExtractFileWithFileNameAndNewFileNameExtractsSymlinkWhenSymlinkE
328329
assertThat(outputFolder.listFiles()[0].getName()).isEqualTo(newFileName);
329330
}
330331

332+
@Test
333+
public void testSymlinkToDirectoryMaintainsSymlink() throws IOException {
334+
verifyZipFileByExtractingAllFiles(getTestArchiveFromResources("zipWithLinkToDirAndFolder.zip"), null, outputFolder, 5, false);
335+
336+
Path aDirectory = Paths.get(outputFolder.getPath(), "a");
337+
Path symlinkToDir = Paths.get(outputFolder.getPath(), "b");
338+
Path aFile = Paths.get(outputFolder.getPath(), "c");
339+
Path symlinkToFile = Paths.get(outputFolder.getPath(), "d");
340+
assertThat(aDirectory).isDirectory();
341+
assertThat(Files.isSymbolicLink(symlinkToDir)).isTrue();
342+
assertThat(aFile).isRegularFile();
343+
assertThat(symlinkToFile).isSymbolicLink();
344+
assertThat(Files.readSymbolicLink(symlinkToDir)).isEqualTo(aDirectory.getFileName());
345+
assertThat(Files.readSymbolicLink(symlinkToFile)).isEqualTo(aFile.getFileName());
346+
}
347+
331348
@Test
332349
public void testExtractFilesThrowsExceptionForWrongPasswordForAes() throws IOException {
333350
ZipParameters zipParameters = createZipParameters(EncryptionMethod.AES, AesKeyStrength.KEY_STRENGTH_256);
Binary file not shown.

0 commit comments

Comments
 (0)