From d709c25cbfdb0be007d3f800f7eddccce965809a Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Tue, 6 Jun 2023 15:14:57 +0000 Subject: [PATCH] 8307887: (fs) Files.createSymbolicLink throws less specific exception when in developer mode and file already exists Reviewed-by: alanb --- .../classes/sun/nio/fs/WindowsFileCopy.java | 12 ++++---- .../sun/nio/fs/WindowsFileSystemProvider.java | 8 ++--- .../sun/nio/fs/WindowsLinkSupport.java | 30 +++++++++++++++++++ .../sun/nio/fs/WindowsNativeDispatcher.java | 15 +--------- 4 files changed, 41 insertions(+), 24 deletions(-) diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsFileCopy.java b/src/java.base/windows/classes/sun/nio/fs/WindowsFileCopy.java index 6be64e8bc9c..11fd13c1b8e 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsFileCopy.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsFileCopy.java @@ -238,9 +238,9 @@ class WindowsFileCopy { } else { String linkTarget = WindowsLinkSupport.readLink(source); int flags = SYMBOLIC_LINK_FLAG_DIRECTORY; - CreateSymbolicLink(targetPath, - WindowsPath.addPrefixIfNeeded(linkTarget), - flags); + WindowsLinkSupport.createSymbolicLink(targetPath, + WindowsPath.addPrefixIfNeeded(linkTarget), + flags); } } catch (WindowsException x) { x.rethrowAsIOException(target); @@ -441,9 +441,9 @@ class WindowsFileCopy { CreateDirectory(targetPath, 0L); } else { String linkTarget = WindowsLinkSupport.readLink(source); - CreateSymbolicLink(targetPath, - WindowsPath.addPrefixIfNeeded(linkTarget), - SYMBOLIC_LINK_FLAG_DIRECTORY); + WindowsLinkSupport.createSymbolicLink(targetPath, + WindowsPath.addPrefixIfNeeded(linkTarget), + SYMBOLIC_LINK_FLAG_DIRECTORY); } } catch (WindowsException x) { x.rethrowAsIOException(target); diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java b/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java index f27ea450606..d76ad8b6f8e 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2023, 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 @@ -594,9 +594,9 @@ class WindowsFileSystemProvider // create the link try { - CreateSymbolicLink(link.getPathForWin32Calls(), - WindowsPath.addPrefixIfNeeded(target.toString()), - flags); + WindowsLinkSupport.createSymbolicLink(link.getPathForWin32Calls(), + WindowsPath.addPrefixIfNeeded(target.toString()), + flags); } catch (WindowsException x) { if (x.lastError() == ERROR_INVALID_REPARSE_DATA) { x.rethrowAsIOException(link, target); diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsLinkSupport.java b/src/java.base/windows/classes/sun/nio/fs/WindowsLinkSupport.java index 0aa385518d7..4e844df03f8 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsLinkSupport.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsLinkSupport.java @@ -45,6 +45,36 @@ class WindowsLinkSupport { private WindowsLinkSupport() { } + /** + * Creates a symbolic link, retyring if not privileged + */ + static void createSymbolicLink(String link, String target, int flags) + throws WindowsException + { + try { + CreateSymbolicLink(link, target, flags); + } catch (WindowsException x) { + // Retry if the privilege to create symbolic links is not held + if (x.lastError() == ERROR_PRIVILEGE_NOT_HELD) { + flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; + try { + CreateSymbolicLink(link, target, flags); + return; + } catch (WindowsException y) { + // Throw an exception if and only if it is not due to symbolic link creation + // privilege not being held (ERROR_PRIVILEGE_NOT_HELD) nor the + // SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE flag not being recognized + // (ERROR_INVALID_PARAMETER). The latter will occur for Windows builds + // older than 14972. + int lastError = y.lastError(); + if (lastError != ERROR_PRIVILEGE_NOT_HELD && lastError != ERROR_INVALID_PARAMETER) + throw y; + } + } + throw x; + } + } + /** * Returns the target of a symbolic link */ diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java b/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java index 26cbe6b96b9..34d748f4150 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2023, 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 @@ -975,19 +975,6 @@ class WindowsNativeDispatcher { 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();