From: Felix Kollmann Date: Wed, 18 Apr 2018 21:04:49 +0000 (+0000) Subject: os: enable symlink creation on Windows 10 X-Git-Tag: go1.11beta1~760 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=c23afa9ddb1180b929ba09a7d96710677a2a4b45;p=gostls13.git os: enable symlink creation on Windows 10 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 Reviewed-by: Alex Brainman --- diff --git a/src/internal/syscall/windows/symlink_windows.go b/src/internal/syscall/windows/symlink_windows.go new file mode 100644 index 0000000000..f2bcd4c4d0 --- /dev/null +++ b/src/internal/syscall/windows/symlink_windows.go @@ -0,0 +1,14 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +import "syscall" + +const ( + ERROR_INVALID_PARAMETER syscall.Errno = 87 + + // symlink support for CreateSymbolicLink() starting with Windows 10 (1703, v10.0.14972) + SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 0x2 +) diff --git a/src/os/file_windows.go b/src/os/file_windows.go index 8ace9c0c7f..a17c6e2ac3 100644 --- a/src/os/file_windows.go +++ b/src/os/file_windows.go @@ -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} } diff --git a/src/os/os_windows_test.go b/src/os/os_windows_test.go index 25f93cf131..faf0d99992 100644 --- a/src/os/os_windows_test.go +++ b/src/os/os_windows_test.go @@ -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 +}