From e162ca57b05bf62b6e437d5ddd558eda40f907b6 Mon Sep 17 00:00:00 2001 From: Cyberboss Date: Tue, 2 Oct 2018 13:46:32 -0400 Subject: [PATCH] Fix and improve windows symbolic link creation --- .../IO/WindowsSymlinkFactory.cs | 16 ++++++++++++++-- src/Tgstation.Server.Host/NativeMethods.cs | 13 ++++++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/Tgstation.Server.Host/IO/WindowsSymlinkFactory.cs b/src/Tgstation.Server.Host/IO/WindowsSymlinkFactory.cs index d6b0da449c..e1b54d7eca 100644 --- a/src/Tgstation.Server.Host/IO/WindowsSymlinkFactory.cs +++ b/src/Tgstation.Server.Host/IO/WindowsSymlinkFactory.cs @@ -21,11 +21,23 @@ namespace Tgstation.Server.Host.IO throw new ArgumentNullException(nameof(linkPath)); //check if its not a file - var flags = File.Exists(targetPath) ? 2 : 3; //SYMBOLIC_LINK_FLAG_DIRECTORY and SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE on win10 1607+ developer mode + var flags = File.Exists(targetPath) ? NativeMethods.CreateSymbolicLinkFlags.None : NativeMethods.CreateSymbolicLinkFlags.Directory; + + flags |= NativeMethods.CreateSymbolicLinkFlags.AllowUnprivilegedCreate; cancellationToken.ThrowIfCancellationRequested(); if (!NativeMethods.CreateSymbolicLink(linkPath, targetPath, flags)) - throw new Win32Exception(Marshal.GetLastWin32Error()); + { + var error = Marshal.GetLastWin32Error(); + if (error == 87) //INVALID_PARAMETER, SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE isn't supported + { + flags &= ~NativeMethods.CreateSymbolicLinkFlags.AllowUnprivilegedCreate; + if (NativeMethods.CreateSymbolicLink(linkPath, targetPath, flags)) + return; + error = Marshal.GetLastWin32Error(); + } + throw new Win32Exception(error); + } }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current); } } diff --git a/src/Tgstation.Server.Host/NativeMethods.cs b/src/Tgstation.Server.Host/NativeMethods.cs index 6b130f9aac..bcc1865686 100644 --- a/src/Tgstation.Server.Host/NativeMethods.cs +++ b/src/Tgstation.Server.Host/NativeMethods.cs @@ -9,6 +9,17 @@ namespace Tgstation.Server.Host /// static class NativeMethods { + /// + /// See https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createsymboliclinka#parameters + /// + [Flags] + public enum CreateSymbolicLinkFlags : int + { + None = 0, + Directory = 1, + AllowUnprivilegedCreate = 2 + } + /// /// See https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowthreadprocessid /// @@ -54,6 +65,6 @@ namespace Tgstation.Server.Host /// See https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createsymboliclinkw /// [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, int dwFlags); + public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, CreateSymbolicLinkFlags dwFlags); } }