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