src/os/os_test.go | 18 ++++++++++++++++++ src/syscall/syscall_windows.go | 3 +++ diff --git a/src/os/os_test.go b/src/os/os_test.go index f1755dfa9139f840a31899a7c0a53e4d1374c934..24a1d84b16f490a462532f6212b8b1cea57e49d6 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -2174,6 +2174,24 @@ t.Fatalf("writeFile: after truncate have %q want %q", s, "new") } } +func TestOpenFileCreateExclDanglingSymlink(t *testing.T) { + defer chtmpdir(t)() + const link = "link" + if err := Symlink("does_not_exist", link); err != nil { + t.Fatal(err) + } + f, err := OpenFile(link, O_WRONLY|O_CREATE|O_EXCL, 0o666) + if err == nil { + f.Close() + } + if !errors.Is(err, ErrExist) { + t.Errorf("OpenFile of a dangling symlink with O_CREATE|O_EXCL = %v, want ErrExist", err) + } + if _, err := Stat(link); err == nil { + t.Errorf("OpenFile of a dangling symlink with O_CREATE|O_EXCL created a file") + } +} + func TestStatDirWithTrailingSlash(t *testing.T) { t.Parallel() diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index d49ee522c4fe883fd1f27ec05348d6d154b30a96..bbc1a11784be0e504d151612b411c17c19867134 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -406,6 +406,9 @@ return h, e } } } + if createmode == CREATE_NEW { + attrs |= FILE_FLAG_OPEN_REPARSE_POINT // don't follow symlinks + } if createmode == OPEN_EXISTING && access == GENERIC_READ { // Necessary for opening directory handles. attrs |= FILE_FLAG_BACKUP_SEMANTICS