Skip to content

Commit

Permalink
syscall: keep write access when O_TRUNC is used on Windows
Browse files Browse the repository at this point in the history
CL 618836 introduces a regression where O_APPEND and O_TRUNC could
not be used together on Windows.

This CL fixes the issue by keeping the write access when O_TRUNC is used
, which is required when overwriting data (as per the file
access rights docs: https://learn.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants).

Fixes #69902.

Change-Id: I77ec60ca6929124dd4490bdad6c3280c4db3efcb
Reviewed-on: https://go-review.googlesource.com/c/go/+/620575
Reviewed-by: Ian Lance Taylor <iant@google.com>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Damien Neil <dneil@google.com>
  • Loading branch information
qmuntal committed Oct 18, 2024
1 parent e45c125 commit 6853d89
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 11 deletions.
6 changes: 5 additions & 1 deletion src/syscall/syscall_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,12 @@ func Open(name string, flag int, perm uint32) (fd Handle, err error) {
access |= GENERIC_WRITE
}
if flag&O_APPEND != 0 {
access &^= GENERIC_WRITE
access |= FILE_APPEND_DATA
// Remove GENERIC_WRITE access unless O_TRUNC is set,
// in which case we need it to truncate the file.
if flag&O_TRUNC == 0 {
access &^= GENERIC_WRITE
}
}
sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE)
var sa *SecurityAttributes
Expand Down
30 changes: 20 additions & 10 deletions src/syscall/syscall_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,39 @@ import (
"testing"
)

func TestOpen_Dir(t *testing.T) {
func TestOpen(t *testing.T) {
t.Parallel()

dir := t.TempDir()
file := filepath.Join(dir, "a")
f, err := os.Create(file)
if err != nil {
t.Fatal(err)
}
f.Close()

tests := []struct {
path string
flag int
err error
}{
{syscall.O_RDONLY, nil},
{syscall.O_CREAT, nil},
{syscall.O_RDONLY | syscall.O_CREAT, nil},
{syscall.O_RDONLY | syscall.O_TRUNC, syscall.ERROR_ACCESS_DENIED},
{syscall.O_WRONLY | syscall.O_RDWR, syscall.EISDIR},
{syscall.O_WRONLY, syscall.EISDIR},
{syscall.O_RDWR, syscall.EISDIR},
{dir, syscall.O_RDONLY, nil},
{dir, syscall.O_CREAT, nil},
{dir, syscall.O_RDONLY | syscall.O_CREAT, nil},
{file, syscall.O_APPEND | syscall.O_WRONLY | os.O_CREATE, nil},
{file, syscall.O_APPEND | syscall.O_WRONLY | os.O_CREATE | os.O_TRUNC, nil},
{dir, syscall.O_RDONLY | syscall.O_TRUNC, syscall.ERROR_ACCESS_DENIED},
{dir, syscall.O_WRONLY | syscall.O_RDWR, syscall.EISDIR},
{dir, syscall.O_WRONLY, syscall.EISDIR},
{dir, syscall.O_RDWR, syscall.EISDIR},
}
for i, tt := range tests {
h, err := syscall.Open(dir, tt.flag, 0)
h, err := syscall.Open(tt.path, tt.flag, 0o660)
if err == nil {
syscall.CloseHandle(h)
}
if err != tt.err {
t.Errorf("%d: Open got %v, want %v", i, err, tt.err)
t.Errorf("%d: Open got %q, want %q", i, err, tt.err)
}
}
}
Expand Down

0 comments on commit 6853d89

Please sign in to comment.