8221852: SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE should be selected at runtime, not build time
Reviewed-by: alanb, shade
--- a/src/java.base/windows/classes/sun/nio/fs/WindowsConstants.java Tue Apr 09 09:49:36 2019 -0700
+++ b/src/java.base/windows/classes/sun/nio/fs/WindowsConstants.java Tue Apr 09 12:17:03 2019 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, Oracle and/or its affiliates. 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
@@ -75,6 +75,7 @@
public static final int IO_REPARSE_TAG_SYMLINK = 0xA000000C;
public static final int MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024;
public static final int SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1;
+ public static final int SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 0x2;
// volume flags
public static final int FILE_CASE_SENSITIVE_SEARCH = 0x00000001;
@@ -104,6 +105,7 @@
public static final int ERROR_MORE_DATA = 234;
public static final int ERROR_DIRECTORY = 267;
public static final int ERROR_NOTIFY_ENUM_DIR = 1022;
+ public static final int ERROR_PRIVILEGE_NOT_HELD = 1314;
public static final int ERROR_NONE_MAPPED = 1332;
public static final int ERROR_NOT_A_REPARSE_POINT = 4390;
public static final int ERROR_INVALID_REPARSE_DATA = 4392;
--- a/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java Tue Apr 09 09:49:36 2019 -0700
+++ b/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java Tue Apr 09 12:17:03 2019 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, Oracle and/or its affiliates. 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
@@ -29,6 +29,8 @@
import java.security.PrivilegedAction;
import jdk.internal.misc.Unsafe;
+import static sun.nio.fs.WindowsConstants.*;
+
/**
* Win32 and library calls.
*/
@@ -920,6 +922,12 @@
* LPCWSTR lpTargetFileName,
* DWORD dwFlags
* )
+ *
+ * Creates a symbolic link, conditionally retrying with the addition of
+ * the flag SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE if the initial
+ * attempt fails with ERROR_PRIVILEGE_NOT_HELD. If the retry fails, throw
+ * the original exception due to ERROR_PRIVILEGE_NOT_HELD. The retry will
+ * succeed only on Windows build 14972 or later if Developer Mode is on.
*/
static void CreateSymbolicLink(String link, String target, int flags)
throws WindowsException
@@ -929,6 +937,19 @@
try {
CreateSymbolicLink0(linkBuffer.address(), targetBuffer.address(),
flags);
+ } catch (WindowsException x) {
+ if (x.lastError() == ERROR_PRIVILEGE_NOT_HELD) {
+ flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
+ try {
+ CreateSymbolicLink0(linkBuffer.address(),
+ targetBuffer.address(), flags);
+ return;
+ } catch (WindowsException ignored) {
+ // Will fail with ERROR_INVALID_PARAMETER for Windows
+ // builds older than 14972.
+ }
+ }
+ throw x;
} finally {
targetBuffer.release();
linkBuffer.release();
--- a/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c Tue Apr 09 09:49:36 2019 -0700
+++ b/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c Tue Apr 09 12:17:03 2019 -0700
@@ -1063,17 +1063,7 @@
LPCWSTR link = jlong_to_ptr(linkAddress);
LPCWSTR target = jlong_to_ptr(targetAddress);
- // Allow creation of symbolic links when the process is not elevated.
- // Developer Mode must be enabled for this option to function, otherwise
- // it will be ignored. Check that symbol is available in current build SDK.
- DWORD dwFlags = (DWORD)flags;
-#ifdef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
- dwFlags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
-#endif
-
- // On Windows 64-bit this appears to succeed even when there are
- // insufficient privileges
- if (CreateSymbolicLinkW(link, target, dwFlags) == 0)
+ if (CreateSymbolicLinkW(link, target, (DWORD)flags) == 0)
throwWindowsException(env, GetLastError());
}