Skip to content

Commit 0b4168f

Browse files
committed
syscall: only remove write data access when O_APPEND is set on Windows
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 <[email protected]> Reviewed-by: Michael Pratt <[email protected]> Reviewed-by: Damien Neil <[email protected]>
1 parent 87c03bd commit 0b4168f

File tree

3 files changed

+32
-3
lines changed

3 files changed

+32
-3
lines changed

src/os/os_test.go

+26
Original file line numberDiff line numberDiff line change
@@ -3593,3 +3593,29 @@ func TestCopyFSWithSymlinks(t *testing.T) {
35933593
t.Fatal("comparing two directories:", err)
35943594
}
35953595
}
3596+
3597+
func TestAppendDoesntOverwrite(t *testing.T) {
3598+
name := filepath.Join(t.TempDir(), "file")
3599+
if err := WriteFile(name, []byte("hello"), 0666); err != nil {
3600+
t.Fatal(err)
3601+
}
3602+
f, err := OpenFile(name, O_APPEND|O_WRONLY, 0)
3603+
if err != nil {
3604+
t.Fatal(err)
3605+
}
3606+
if _, err := f.Write([]byte(" world")); err != nil {
3607+
f.Close()
3608+
t.Fatal(err)
3609+
}
3610+
if err := f.Close(); err != nil {
3611+
t.Fatal(err)
3612+
}
3613+
got, err := ReadFile(name)
3614+
if err != nil {
3615+
t.Fatal(err)
3616+
}
3617+
want := "hello world"
3618+
if string(got) != want {
3619+
t.Fatalf("got %q, want %q", got, want)
3620+
}
3621+
}

src/syscall/syscall_windows.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -362,12 +362,14 @@ func Open(name string, flag int, perm uint32) (fd Handle, err error) {
362362
access |= GENERIC_WRITE
363363
}
364364
if flag&O_APPEND != 0 {
365-
access |= FILE_APPEND_DATA
366-
// Remove GENERIC_WRITE access unless O_TRUNC is set,
367-
// in which case we need it to truncate the file.
365+
// Remove GENERIC_WRITE unless O_TRUNC is set, in which case we need it to truncate the file.
366+
// We can't just remove FILE_WRITE_DATA because GENERIC_WRITE without FILE_WRITE_DATA
367+
// starts appending at the beginning of the file rather than at the end.
368368
if flag&O_TRUNC == 0 {
369369
access &^= GENERIC_WRITE
370370
}
371+
// Set all access rights granted by GENERIC_WRITE except for FILE_WRITE_DATA.
372+
access |= FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES | _FILE_WRITE_EA | STANDARD_RIGHTS_WRITE | SYNCHRONIZE
371373
}
372374
sharemode := uint32(FILE_SHARE_READ | FILE_SHARE_WRITE)
373375
var sa *SecurityAttributes

src/syscall/types_windows.go

+1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ const (
9393

9494
FILE_LIST_DIRECTORY = 0x00000001
9595
FILE_APPEND_DATA = 0x00000004
96+
_FILE_WRITE_EA = 0x00000010
9697
FILE_WRITE_ATTRIBUTES = 0x00000100
9798

9899
FILE_SHARE_READ = 0x00000001

0 commit comments

Comments
 (0)