Created
October 20, 2018 17:59
-
-
Save Cyberboss/a6e673d4647d27895c77bac860636a40 to your computer and use it in GitHub Desktop.
Symlink test one off
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using BetterWin32Errors; | |
using System.IO; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using System.Runtime.InteropServices; | |
using System.Text; | |
namespace Tgstation.Server.Host | |
{ | |
/// <summary> | |
/// Native methods used by the code | |
/// </summary> | |
static class NativeMethods | |
{ | |
/// <summary> | |
/// See https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createsymboliclinka#parameters | |
/// </summary> | |
[Flags] | |
public enum CreateSymbolicLinkFlags : int | |
{ | |
None = 0, | |
Directory = 1, | |
AllowUnprivilegedCreate = 2 | |
} | |
/// <summary> | |
/// See https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowthreadprocessid | |
/// </summary> | |
[DllImport("user32.dll")] | |
public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int lpdwProcessId); | |
/// <summary> | |
/// See https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-findwindoww | |
/// </summary> | |
[DllImport("user32.dll", CharSet = CharSet.Unicode)] | |
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); | |
/// <summary> | |
/// See https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-sendmessage | |
/// </summary> | |
[DllImport("user32.dll")] | |
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam); | |
/// <summary> | |
/// See https://msdn.microsoft.com/en-us/library/ms633493(v=VS.85).aspx | |
/// </summary> | |
public delegate bool EnumWindowProc(IntPtr hwnd, IntPtr lParam); | |
/// <summary> | |
/// See https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-enumchildwindows | |
/// </summary> | |
[DllImport("user32.dll")] | |
public static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr lParam); | |
/// <summary> | |
/// See https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowtextw | |
/// </summary> | |
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)] | |
public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); | |
/// <summary> | |
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa378184(v=vs.85).aspx | |
/// </summary> | |
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] | |
public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken); | |
/// <summary> | |
/// See https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-createsymboliclinkw | |
/// </summary> | |
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] | |
public static extern bool CreateSymbolicLink(string lpSymlinkFileName, string lpTargetFileName, CreateSymbolicLinkFlags dwFlags); | |
} | |
} | |
namespace Tgstation.Server.Host.IO | |
{ | |
/// <summary> | |
/// <see cref="ISymlinkFactory"/> for windows systems | |
/// </summary> | |
sealed class WindowsSymlinkFactory | |
{ | |
/// <inheritdoc /> | |
public Task CreateSymbolicLink(string targetPath, string linkPath, CancellationToken cancellationToken) => Task.Factory.StartNew(() => | |
{ | |
if (targetPath == null) | |
throw new ArgumentNullException(nameof(targetPath)); | |
if (linkPath == null) | |
throw new ArgumentNullException(nameof(linkPath)); | |
//check if its not a file | |
var flags = File.Exists(targetPath) ? NativeMethods.CreateSymbolicLinkFlags.None : NativeMethods.CreateSymbolicLinkFlags.Directory; | |
flags |= NativeMethods.CreateSymbolicLinkFlags.AllowUnprivilegedCreate; | |
cancellationToken.ThrowIfCancellationRequested(); | |
if (!NativeMethods.CreateSymbolicLink(linkPath, targetPath, flags)) | |
{ | |
if (Win32Exception.GetLastWin32Error() == Win32Error.ERROR_INVALID_PARAMETER) //SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE isn't supported | |
{ | |
flags &= ~NativeMethods.CreateSymbolicLinkFlags.AllowUnprivilegedCreate; | |
if (NativeMethods.CreateSymbolicLink(linkPath, targetPath, flags)) | |
return; | |
} | |
throw new Win32Exception(); | |
} | |
}, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current); | |
} | |
} | |
namespace ConsoleApp2 | |
{ | |
class Program | |
{ | |
static async Task Main(string[] args) | |
{ | |
try | |
{ | |
Console.WriteLine("Symlinking \"C:\\TGS4_INSTANCES\\STARTREK13\\Configuration\\GameStaticFiles\\config\" to \"C:\\TGS4_INSTANCES\\STARTREK13\\Game\\53278a00-92e5-48ee-9083-7635367f0a28\\A\\config\""); | |
await new Tgstation.Server.Host.IO.WindowsSymlinkFactory().CreateSymbolicLink("C:\\TGS4_INSTANCES\\STARTREK13\\Configuration\\GameStaticFiles\\config", "C:\\TGS4_INSTANCES\\STARTREK13\\Game\\53278a00-92e5-48ee-9083-7635367f0a28\\A\\config", default).ConfigureAwait(false); | |
Console.WriteLine("Done!"); | |
} | |
catch (Exception e) | |
{ | |
Console.WriteLine(e.ToString()); | |
} | |
Console.WriteLine("Press any key to continue..."); | |
Console.ReadKey(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment