Skip to content

Commit 30f4d9e

Browse files
qmuntalgopherbot
authored andcommitted
[release-branch.go1.24] syscall: don't truncate newly created files on Windows
There is no need for syscall.OpenFile to truncate newly created files. Some special Windows files, like the NUL device, can't be truncated, so we should avoid truncating unless it is really necessary. For #71752 Fixes #71836 Change-Id: I8238048594f706f6a5281053d55cfe3dc898828d Reviewed-on: https://go-review.googlesource.com/c/go/+/650276 LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Damien Neil <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> (cherry picked from commit 4267fd3) Reviewed-on: https://go-review.googlesource.com/c/go/+/650597 Reviewed-by: Ian Lance Taylor <[email protected]> Auto-Submit: Ian Lance Taylor <[email protected]> Commit-Queue: Ian Lance Taylor <[email protected]> Reviewed-by: Quim Muntal <[email protected]>
1 parent bb0e5c2 commit 30f4d9e

File tree

3 files changed

+30
-7
lines changed

3 files changed

+30
-7
lines changed

src/os/os_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3848,3 +3848,14 @@ func TestRemoveReadOnlyFile(t *testing.T) {
38483848
}
38493849
})
38503850
}
3851+
3852+
func TestOpenFileDevNull(t *testing.T) {
3853+
// See https://go.dev/issue/71752.
3854+
t.Parallel()
3855+
3856+
f, err := OpenFile(DevNull, O_WRONLY|O_CREATE|O_TRUNC, 0o644)
3857+
if err != nil {
3858+
t.Fatalf("OpenFile(DevNull): %v", err)
3859+
}
3860+
f.Close()
3861+
}

src/syscall/syscall_windows.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ func NewCallbackCDecl(fn any) uintptr {
235235
//sys GetVersion() (ver uint32, err error)
236236
//sys formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
237237
//sys ExitProcess(exitcode uint32)
238-
//sys CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW
238+
//sys createFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval == InvalidHandle || e1 == ERROR_ALREADY_EXISTS ] = CreateFileW
239239
//sys readFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) = ReadFile
240240
//sys writeFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error) = WriteFile
241241
//sys SetFilePointer(handle Handle, lowoffset int32, highoffsetptr *int32, whence uint32) (newlowoffset uint32, err error) [failretval==0xffffffff]
@@ -404,18 +404,20 @@ func Open(name string, flag int, perm uint32) (fd Handle, err error) {
404404
const _FILE_FLAG_WRITE_THROUGH = 0x80000000
405405
attrs |= _FILE_FLAG_WRITE_THROUGH
406406
}
407-
h, err := CreateFile(namep, access, sharemode, sa, createmode, attrs, 0)
408-
if err != nil {
407+
h, err := createFile(namep, access, sharemode, sa, createmode, attrs, 0)
408+
if h == InvalidHandle {
409409
if err == ERROR_ACCESS_DENIED && (flag&O_WRONLY != 0 || flag&O_RDWR != 0) {
410410
// We should return EISDIR when we are trying to open a directory with write access.
411411
fa, e1 := GetFileAttributes(namep)
412412
if e1 == nil && fa&FILE_ATTRIBUTE_DIRECTORY != 0 {
413413
err = EISDIR
414414
}
415415
}
416-
return InvalidHandle, err
416+
return h, err
417417
}
418-
if flag&O_TRUNC == O_TRUNC {
418+
// Ignore O_TRUNC if the file has just been created.
419+
if flag&O_TRUNC == O_TRUNC &&
420+
(createmode == OPEN_EXISTING || (createmode == OPEN_ALWAYS && err == ERROR_ALREADY_EXISTS)) {
419421
err = Ftruncate(h, 0)
420422
if err != nil {
421423
CloseHandle(h)
@@ -1454,3 +1456,13 @@ func GetStartupInfo(startupInfo *StartupInfo) error {
14541456
getStartupInfo(startupInfo)
14551457
return nil
14561458
}
1459+
1460+
func CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) {
1461+
handle, err = createFile(name, access, mode, sa, createmode, attrs, templatefile)
1462+
if handle != InvalidHandle {
1463+
// CreateFileW can return ERROR_ALREADY_EXISTS with a valid handle.
1464+
// We only want to return an error if the handle is invalid.
1465+
err = nil
1466+
}
1467+
return handle, err
1468+
}

src/syscall/zsyscall_windows.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)