]> Cypherpunks repositories - gostls13.git/commitdiff
os: enable symlink creation on Windows 10
authorFelix Kollmann <fk@konsorten.de>
Wed, 18 Apr 2018 21:04:49 +0000 (21:04 +0000)
committerAlex Brainman <alex.brainman@gmail.com>
Thu, 19 Apr 2018 10:10:22 +0000 (10:10 +0000)
Fixes #22874

Change-Id: Ia30fc8df39e88fbc2939a4490c34da8dd5815a94
GitHub-Last-Rev: 3ba7abcc96ee02837fbfd65c044326c2f1923020
GitHub-Pull-Request: golang/go#24307
Reviewed-on: https://go-review.googlesource.com/99337
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
src/internal/syscall/windows/symlink_windows.go [new file with mode: 0644]
src/os/file_windows.go
src/os/os_windows_test.go

diff --git a/src/internal/syscall/windows/symlink_windows.go b/src/internal/syscall/windows/symlink_windows.go
new file mode 100644 (file)
index 0000000..f2bcd4c
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright 2018 The Go Authors. All rights reserved.\r
+// Use of this source code is governed by a BSD-style\r
+// license that can be found in the LICENSE file.\r
+\r
+package windows\r
+\r
+import "syscall"\r
+\r
+const (\r
+       ERROR_INVALID_PARAMETER syscall.Errno = 87\r
+\r
+       // symlink support for CreateSymbolicLink() starting with Windows 10 (1703, v10.0.14972)\r
+       SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 0x2\r
+)\r
index 8ace9c0c7fa4bed73de7bb72ef66fbe9107683a0..a17c6e2ac337497e572f5b172aba6859066ba945 100644 (file)
@@ -373,11 +373,20 @@ func Symlink(oldname, newname string) error {
                return &LinkError{"symlink", oldname, newname, err}
        }
 
-       var flags uint32
+       var flags uint32 = windows.SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
        if isdir {
                flags |= syscall.SYMBOLIC_LINK_FLAG_DIRECTORY
        }
        err = syscall.CreateSymbolicLink(n, o, flags)
+
+       if err != nil {
+               // the unprivileged create flag is unsupported
+               // below Windows 10 (1703, v10.0.14972). retry without it.
+               flags &^= windows.SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
+
+               err = syscall.CreateSymbolicLink(n, o, flags)
+       }
+
        if err != nil {
                return &LinkError{"symlink", oldname, newname, err}
        }
index 25f93cf131808ae74696d01cd50e0f5f156b9b1f..faf0d99992524dcd933018cac38c51d6bcb3284b 100644 (file)
@@ -1011,3 +1011,47 @@ func TestWindowsDevNullFile(t *testing.T) {
                t.Errorf(`"NUL" and "nul" are not the same file`)
        }
 }
+
+// TestSymlinkCreation verifies that creating a symbolic link
+// works on Windows when developer mode is active.
+// This is supported starting Windows 10 (1703, v10.0.14972).
+func TestSymlinkCreation(t *testing.T) {
+       if !isWindowsDeveloperModeActive() {
+               t.Skip("Windows developer mode is not active")
+       }
+
+       temp, err := ioutil.TempDir("", "TestSymlinkCreation")
+       if err != nil {
+               t.Fatal(err)
+       }
+       defer os.RemoveAll(temp)
+
+       dummyFile := filepath.Join(temp, "file")
+       err = ioutil.WriteFile(dummyFile, []byte(""), 0644)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       linkFile := filepath.Join(temp, "link")
+       err = os.Symlink(dummyFile, linkFile)
+       if err != nil {
+               t.Fatal(err)
+       }
+}
+
+// isWindowsDeveloperModeActive checks whether or not the developer mode is active on Windows 10.
+// Returns false for prior Windows versions.
+// see https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development
+func isWindowsDeveloperModeActive() bool {
+       key, err := registry.OpenKey(registry.LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\AppModelUnlock", registry.READ)
+       if err != nil {
+               return false
+       }
+
+       val, _, err := key.GetIntegerValue("AllowDevelopmentWithoutDevLicense")
+       if err != nil {
+               return false
+       }
+
+       return val != 0
+}