mirror of https://github.com/golang/go.git
syscall: preserve Windows file permissions for O_CREAT|O_TRUNC
On Windows, calling syscall.Open(file, O_CREAT|O_TRUNC, 0) for a file that already exists would change the file to be read-only. That is not how the Unix syscall.Open behaves, so avoid it on Windows by calling CreateFile twice if necessary. Fixes #38225 Change-Id: I70097fca8863df427cc8a97b9376a9ffc69c6318 Reviewed-on: https://go-review.googlesource.com/c/go/+/234534 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
This commit is contained in:
parent
aeab403174
commit
567556d786
|
|
@ -2539,3 +2539,34 @@ func isDeadlineExceeded(err error) bool {
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Test that opening a file does not change its permissions. Issue 38225.
|
||||
func TestOpenFileKeepsPermissions(t *testing.T) {
|
||||
t.Parallel()
|
||||
dir := t.TempDir()
|
||||
name := filepath.Join(dir, "x")
|
||||
f, err := Create(name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
f, err = OpenFile(name, O_WRONLY|O_CREATE|O_TRUNC, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if fi, err := f.Stat(); err != nil {
|
||||
t.Error(err)
|
||||
} else if fi.Mode()&0222 == 0 {
|
||||
t.Errorf("f.Stat.Mode after OpenFile is %v, should be writable", fi.Mode())
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if fi, err := Stat(name); err != nil {
|
||||
t.Error(err)
|
||||
} else if fi.Mode()&0222 == 0 {
|
||||
t.Errorf("Stat after OpenFile is %v, should be writable", fi.Mode())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -339,6 +339,26 @@ func Open(path string, mode int, perm uint32) (fd Handle, err error) {
|
|||
var attrs uint32 = FILE_ATTRIBUTE_NORMAL
|
||||
if perm&S_IWRITE == 0 {
|
||||
attrs = FILE_ATTRIBUTE_READONLY
|
||||
if createmode == CREATE_ALWAYS {
|
||||
// We have been asked to create a read-only file.
|
||||
// If the file already exists, the semantics of
|
||||
// the Unix open system call is to preserve the
|
||||
// existing permissions. If we pass CREATE_ALWAYS
|
||||
// and FILE_ATTRIBUTE_READONLY to CreateFile,
|
||||
// and the file already exists, CreateFile will
|
||||
// change the file permissions.
|
||||
// Avoid that to preserve the Unix semantics.
|
||||
h, e := CreateFile(pathp, access, sharemode, sa, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
|
||||
switch e {
|
||||
case ERROR_FILE_NOT_FOUND, _ERROR_BAD_NETPATH, ERROR_PATH_NOT_FOUND:
|
||||
// File does not exist. These are the same
|
||||
// errors as Errno.Is checks for ErrNotExist.
|
||||
// Carry on to create the file.
|
||||
default:
|
||||
// Success or some different error.
|
||||
return h, e
|
||||
}
|
||||
}
|
||||
}
|
||||
h, e := CreateFile(pathp, access, sharemode, sa, createmode, attrs, 0)
|
||||
return h, e
|
||||
|
|
|
|||
Loading…
Reference in New Issue