Commit c23afa9d authored by Felix Kollmann's avatar Felix Kollmann Committed by Alex Brainman

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 <gobot@golang.org>
Reviewed-by: default avatarAlex Brainman <alex.brainman@gmail.com>
parent c6bbfbe7
// 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
)
...@@ -373,11 +373,20 @@ func Symlink(oldname, newname string) error { ...@@ -373,11 +373,20 @@ func Symlink(oldname, newname string) error {
return &LinkError{"symlink", oldname, newname, err} return &LinkError{"symlink", oldname, newname, err}
} }
var flags uint32 var flags uint32 = windows.SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
if isdir { if isdir {
flags |= syscall.SYMBOLIC_LINK_FLAG_DIRECTORY flags |= syscall.SYMBOLIC_LINK_FLAG_DIRECTORY
} }
err = syscall.CreateSymbolicLink(n, o, flags) 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 { if err != nil {
return &LinkError{"symlink", oldname, newname, err} return &LinkError{"symlink", oldname, newname, err}
} }
......
...@@ -1011,3 +1011,47 @@ func TestWindowsDevNullFile(t *testing.T) { ...@@ -1011,3 +1011,47 @@ func TestWindowsDevNullFile(t *testing.T) {
t.Errorf(`"NUL" and "nul" are not the same file`) 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
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment