diff --git a/src/java.base/share/classes/jdk/internal/access/JdkNioZipfsAccess.java b/src/java.base/share/classes/jdk/internal/access/JdkNioZipfsAccess.java new file mode 100644 index 000000000000..a7789a4beef5 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/access/JdkNioZipfsAccess.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2026 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.access; + +import java.nio.file.Path; + +/** + * SharedSecrets interface used for the access from java.text.Bidi + */ + +public interface JdkNioZipfsAccess { + + // java.awt.font.TextAttribute constants + public boolean isSymbolicLink(Path path); +} diff --git a/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java b/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java index 4d70095b157a..c02f76f28a91 100644 --- a/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java +++ b/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java @@ -109,6 +109,8 @@ public class SharedSecrets { @Stable private static JavaxCryptoSealedObjectAccess javaxCryptoSealedObjectAccess; @Stable private static JavaxCryptoSpecAccess javaxCryptoSpecAccess; @Stable private static JavaxSecurityAccess javaxSecurityAccess; + // SapMachine 2026-04-14: Support for symlink detection in zipfs. + @Stable private static JdkNioZipfsAccess jdkNioZipfsAccess; public static void setJavaUtilCollectionAccess(JavaUtilCollectionAccess juca) { javaUtilCollectionAccess = juca; @@ -537,4 +539,14 @@ private static void ensureClassInitialized(Class c) { MethodHandles.lookup().ensureInitialized(c); } catch (IllegalAccessException e) {} } + + // SapMachine 2026-04-14 + public static void setJdkNioZipfsAccess(JdkNioZipfsAccess access) { + jdkNioZipfsAccess = access; + } + + // SapMachine 2026-04-14 + public static JdkNioZipfsAccess getJdkNioZipfsAccess() { + return jdkNioZipfsAccess; + } } diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index a16a66066074..e1de25572ed7 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -167,6 +167,8 @@ jdk.net, // SapMachine 2024-06-12: process group extension jdk.sapext, + // SapMachine 2026-04-13: symlink support for zipfs entries in sapext. + jdk.zipfs, jdk.sctp, jdk.crypto.cryptoki; exports jdk.internal.classfile.components to diff --git a/src/jdk.sapext/share/classes/com/sap/jdk/ext/util/ZipfsUtils.java b/src/jdk.sapext/share/classes/com/sap/jdk/ext/util/ZipfsUtils.java new file mode 100644 index 000000000000..0c2ef76b28e9 --- /dev/null +++ b/src/jdk.sapext/share/classes/com/sap/jdk/ext/util/ZipfsUtils.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2026 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + package com.sap.jdk.ext.util; + +import java.nio.file.Path; + +import jdk.internal.access.JdkNioZipfsAccess; +import jdk.internal.access.SharedSecrets; + +public class ZipfsUtils { + + // Silence warning about implicit ctor. + private ZipfsUtils() { + } + + /** + * Returns true if the given path is a {@link jdk.nio.zipfs.ZipPath} which + * represents a symbolic link. + * + * @param path The path in the zipfs. + * @return true if the path represents a symbolic link. + */ + public static boolean isSymbolicLink(Path path) { + JdkNioZipfsAccess access = SharedSecrets.getJdkNioZipfsAccess(); + + if (access == null) { + return false; + } + + return access.isSymbolicLink(path); + } +} diff --git a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java index 3223ff9dccd4..e8421bddccba 100644 --- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java +++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystem.java @@ -3645,4 +3645,17 @@ public boolean equals(Object other) { oname, 0, oname.length); } } + + // SapMachine 2026-04-14: Returns true if the resolved path points to a symnbolic link. + boolean isSymlink(byte[] path) { + IndexNode inode = getInode(path); + + if ((inode != null) && (inode.pos != -1)) { + long attrEx = ZipConstants.CENATX(cen, inode.pos); + + return (attrEx & 0xF0000000L) == 0xA0000000L; + } + + return false; + } } diff --git a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java index adfa975c1c37..161611f61c56 100644 --- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java +++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java @@ -62,6 +62,25 @@ final class ZipPath implements Path { private volatile int[] offsets; private int hashcode = 0; // cached hashcode (created lazily) + // SapMachine 2026-04-14: Support for symlink detectiun. + static class JdkNioZipfsAccessImpl implements jdk.internal.access.JdkNioZipfsAccess { + public boolean isSymbolicLink(Path path) { + if (!(path instanceof ZipPath)) { + return false; + } + + ZipPath zipPath = (ZipPath) path; + byte[] resolvedPath = zipPath.getResolvedPath(); + + return zipPath.zfs.isSymlink(resolvedPath); + } + } + + // SapMachine 2026-04-14: Support for symlink detectiun. + static { + jdk.internal.access.SharedSecrets.setJdkNioZipfsAccess(new JdkNioZipfsAccessImpl()); + } + ZipPath(ZipFileSystem zfs, byte[] path) { this(zfs, path, false); } diff --git a/test/jdk/sap/ZipfsUtilsTest.java b/test/jdk/sap/ZipfsUtilsTest.java new file mode 100644 index 000000000000..909346ffafb4 --- /dev/null +++ b/test/jdk/sap/ZipfsUtilsTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2026 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @summary Runs the test for com.sap.jdk.ext.util.ZipfsUtils. + * + * @run junit ZipfsUtilsTest + */ + +import java.io.File; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.util.Map; + +import com.sap.jdk.ext.util.ZipfsUtils; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ZipfsUtilsTest { + + @Test + public void basicTest() throws Exception { + File file = new File(System.getProperty("test.src", "."), "zip-with-symlink.zip"); + URI uri = new URI("jar", file.toURI().toString(), null); + FileSystem fs = FileSystems.newFileSystem(uri, Map.of()); + assertFalse(ZipfsUtils.isSymbolicLink(fs.getPath("file"))); + assertTrue(ZipfsUtils.isSymbolicLink(fs.getPath("symlink"))); + } +} diff --git a/test/jdk/sap/zip-with-symlink.zip b/test/jdk/sap/zip-with-symlink.zip new file mode 100644 index 000000000000..98c94ff89cf3 Binary files /dev/null and b/test/jdk/sap/zip-with-symlink.zip differ