]> Cypherpunks repositories - gostls13.git/commitdiff
syscall: only remove write data access when O_APPEND is set on Windows
authorqmuntal <quimmuntal@gmail.com>
Wed, 16 Oct 2024 14:38:37 +0000 (16:38 +0200)
committerQuim Muntal <quimmuntal@gmail.com>
Wed, 23 Oct 2024 17:23:13 +0000 (17:23 +0000)
There is no need to remove all write accesses when O_APPEND is set,
only the FILE_WRITE_DATA access. This will allow files opened with
O_APPEND and O_WRONLY to be have their attributes and ACLs modified.

Change-Id: I6fe3b25e87b141a9eb30805f395fec31242fd35d
Reviewed-on: https://go-review.googlesource.com/c/go/+/620615
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
src/os/os_test.go
src/syscall/syscall_windows.go
src/syscall/types_windows.go

index 4db5521fee71af0efb69ae7994028f96df7d448c..5b1c8ba2f0ec28388bb7922c6fbfeb0796a8f6e3 100644 (file)
@@ -3593,3 +3593,29 @@ func TestCopyFSWithSymlinks(t *testing.T) {
                t.Fatal("comparing two directories:", err)
        }
 }
+
+func TestAppendDoesntOverwrite(t *testing.T) {
+       name := filepath.Join(t.TempDir(), "file")
+       if err := WriteFile(name, []byte("hello"), 0666); err != nil {
+               t.Fatal(err)
+       }
+       f, err := OpenFile(name, O_APPEND|O_WRONLY, 0)
+       if err != nil {
+               t.Fatal(err)
+       }
+       if _, err := f.Write([]byte(" world")); err != nil {
+               f.Close()
+               t.Fatal(err)
+       }
+       if err := f.Close(); err != nil {
+               t.Fatal(err)
+       }
+       got, err := ReadFile(name)
+       if err != nil {
+               t.Fatal(err)
+       }
+       want := "hello world"
+       if string(got) != want {
+               t.Fatalf("got %q, want %q", got, want)
+       }
+}
index 67a71dfc766f6bd6b63c98bbcffd19b8a09ee75b..05c29c7b2060ad5813d8cabd0d09dcdd0d4232f3 100644 (file)
@@ -362,12 +362,14 @@ func Open(name string, flag int, perm uint32) (fd Handle, err error) {
                access |= GENERIC_WRITE
        }
        if flag&O_APPEND != 0 {
-               access |= FILE_APPEND_DATA
-               // Remove GENERIC_WRITE access unless O_TRUNC is set,
-               // in which case we need it to truncate the file.
+               // Remove GENERIC_WRITE unless O_TRUNC is set, in which case we need it to truncate the file.
+               // We can't just remove FILE_WRITE_DATA because GENERIC_WRITE without FILE_WRITE_DATA
+               // starts appending at the beginning of the file rather than at the end.
                if flag&O_TRUNC == 0 {
                        access &^= GENERIC_WRITE
                }
+               // Set all access rights granted by GENERIC_WRITE except for FILE_WRITE_DATA.
+               access |= FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | _FILE_WRITE_EA | STANDARD_RIGHTS_WRITE | SYNCHRONIZE
        }
        sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE)
        var sa *SecurityAttributes
index eb1ba06ce667035d05a3300dc47c5853be46fed0..b0fae8a5dc0cec307f817861b553b4f606f36374 100644 (file)
@@ -93,6 +93,7 @@ const (
 
        FILE_LIST_DIRECTORY   = 0x00000001
        FILE_APPEND_DATA      = 0x00000004
+       _FILE_WRITE_EA        = 0x00000010
        FILE_WRITE_ATTRIBUTES = 0x00000100
 
        FILE_SHARE_READ              = 0x00000001