diff --git a/src/java.base/share/classes/java/nio/file/SecureDirectoryStream.java b/src/java.base/share/classes/java/nio/file/SecureDirectoryStream.java index 36c97efefca..7fcf28e55d6 100644 --- a/src/java.base/share/classes/java/nio/file/SecureDirectoryStream.java +++ b/src/java.base/share/classes/java/nio/file/SecureDirectoryStream.java @@ -220,7 +220,11 @@ public interface SecureDirectoryStream * path then it locates the target file (the {@code targetdir} parameter is * ignored). If the {@code existing} parameter is a relative path it is * located relative to the open directory identified by the {@code - * targetdir} parameter. + * targetdir} parameter, unless {@code targetdir} is {@code null}, in which + * case it is located relative to the current working directory. By default, + * symbolic links are followed. If the option + * {@linkplain LinkOption#NOFOLLOW_LINKS NOFOLLOW_LINKS} is present then + * symbolic links are not followed. * * @param link * the link (directory entry) to create @@ -228,6 +232,8 @@ public interface SecureDirectoryStream * the destination directory * @param existing * a path to an existing file + * @param options + * options indicating how symbolic links are handled * * @return the path to the link (directory entry) * @@ -247,7 +253,8 @@ public interface SecureDirectoryStream * * @since 26 */ - T createLink(T link, SecureDirectoryStream targetdir, T existing) + T createLink(T link, SecureDirectoryStream targetdir, T existing, + LinkOption... options) throws IOException; /** diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template b/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template index 6823833582f..1a3a65dec35 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template +++ b/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template @@ -143,11 +143,13 @@ class UnixConstants { // flags used with openat/unlinkat/etc. #if defined(AT_FDCWD) && defined(AT_SYMLINK_NOFOLLOW) && defined(AT_REMOVEDIR) static final int PREFIX_AT_FDCWD = AT_FDCWD; + static final int PREFIX_AT_SYMLINK_FOLLOW = AT_SYMLINK_FOLLOW; static final int PREFIX_AT_SYMLINK_NOFOLLOW = AT_SYMLINK_NOFOLLOW; static final int PREFIX_AT_REMOVEDIR = AT_REMOVEDIR; #else // not supported (dummy values will not be used at runtime). static final int PREFIX_AT_FDCWD = 00; + static final int PREFIX_AT_SYMLINK_FOLLOW = 00; static final int PREFIX_AT_SYMLINK_NOFOLLOW = 00; static final int PREFIX_AT_REMOVEDIR = 00; #endif diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java index 6d97ef0f312..e609ccd98dd 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixNativeDispatcher.java @@ -136,16 +136,17 @@ class UnixNativeDispatcher { /** * linkat(int fd1, const char *name1, int fd2, const char *name2, int flag) */ - static void linkat(int dfd1, UnixPath path1, int dfd2, UnixPath path2) + static void linkat(int dfd1, UnixPath path1, int dfd2, UnixPath path2, + int flag) throws UnixException { try (NativeBuffer buffer1 = copyToNativeBuffer(path1); NativeBuffer buffer2 = copyToNativeBuffer(path2)) { - linkat0(dfd1, buffer1.address(), dfd2, buffer2.address()); + linkat0(dfd1, buffer1.address(), dfd2, buffer2.address(), flag); } } private static native void linkat0(int dfd1, long addr1, - int dfd2, long addr2) + int dfd2, long addr2, int flag) throws UnixException; /** diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixSecureDirectoryStream.java b/src/java.base/unix/classes/sun/nio/fs/UnixSecureDirectoryStream.java index e047b3bb75b..0806a55b8f3 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixSecureDirectoryStream.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixSecureDirectoryStream.java @@ -217,7 +217,7 @@ class UnixSecureDirectoryStream @Override public Path createLink(Path link, SecureDirectoryStream dir, - Path target) + Path target, LinkOption... options) throws IOException { UnixPath linkpath = UnixPath.toUnixPath(link); @@ -229,7 +229,9 @@ class UnixSecureDirectoryStream throw new ClosedDirectoryStreamException(); try { UnixSecureDirectoryStream that = (UnixSecureDirectoryStream)dir; - linkat(that.dfd, targetpath, this.dfd, linkpath); + int targetfd = that != null ? that.dfd : AT_FDCWD; + int flag = Util.followLinks(options) ? AT_SYMLINK_FOLLOW : 0; + linkat(targetfd, targetpath, this.dfd, linkpath, flag); } catch (UnixException x) { x.rethrowAsIOException(linkpath, targetpath); return null; // keep compiler happy diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c index 17fa906f821..84fd738fafb 100644 --- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c @@ -1029,14 +1029,14 @@ Java_sun_nio_fs_UnixNativeDispatcher_link0(JNIEnv* env, jclass this, JNIEXPORT void JNICALL Java_sun_nio_fs_UnixNativeDispatcher_linkat0(JNIEnv* env, jclass this, - int dfd1, long addr1, - int dfd2, long addr2) + jint dfd1, jlong addr1, + jint dfd2, jlong addr2, jint flag) { int err; const char* name1 = (const char*)jlong_to_ptr(addr1); const char* name2 = (const char*)jlong_to_ptr(addr2); - RESTARTABLE(linkat(dfd1, name1, dfd2, name2, AT_SYMLINK_FOLLOW), err); + RESTARTABLE(linkat(dfd1, name1, dfd2, name2, flag), err); if (err == -1) { throwUnixException(env, errno); } diff --git a/test/jdk/java/nio/file/DirectoryStream/SecureDS.java b/test/jdk/java/nio/file/DirectoryStream/SecureDS.java index 24f6c03e1a5..5078e05adae 100644 --- a/test/jdk/java/nio/file/DirectoryStream/SecureDS.java +++ b/test/jdk/java/nio/file/DirectoryStream/SecureDS.java @@ -497,10 +497,6 @@ public class SecureDS { stream.createLink(null, stream, file); shouldNotGetHere(); } catch (NullPointerException x) { } - try { - stream.createLink(link, null, file); - shouldNotGetHere(); - } catch (NullPointerException x) { } try { stream.createLink(link, stream, null); shouldNotGetHere();