]> Cypherpunks repositories - gostls13.git/commitdiff
syscall: keep write access when O_TRUNC is used on Windows
authorqmuntal <quimmuntal@gmail.com>
Wed, 16 Oct 2024 14:18:45 +0000 (16:18 +0200)
committerQuim Muntal <quimmuntal@gmail.com>
Fri, 18 Oct 2024 04:09:36 +0000 (04:09 +0000)
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>
src/syscall/syscall_windows.go
src/syscall/syscall_windows_test.go

index db1f4f2ba4d2cbee083ed0ddf97197c5e50c2a75..67a71dfc766f6bd6b63c98bbcffd19b8a09ee75b 100644 (file)
@@ -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
index ea1e8c9b3c2fa5d3e609d2b67d7b9070569bb699..8b5af9c501dc4553922521ccbc8ea60d6e7c6be3 100644 (file)
@@ -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)
                }
        }
 }