Skip to content

Commit d7384f3

Browse files
iwdgoalexbrainman
authored andcommitted
os: implement File.Chmod on Windows
Fixes: #39606 Change-Id: I4def67ef18bd3ff866b140f6e76cdabe5d51a1c5 Reviewed-on: https://go-review.googlesource.com/c/go/+/250077 Run-TryBot: Alex Brainman <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Alex Brainman <[email protected]>
1 parent 07c1788 commit d7384f3

File tree

6 files changed

+76
-22
lines changed

6 files changed

+76
-22
lines changed

src/internal/poll/fd_posix.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,6 @@ func (fd *FD) Shutdown(how int) error {
2929
return syscall.Shutdown(fd.Sysfd, how)
3030
}
3131

32-
// Fchmod wraps syscall.Fchmod.
33-
func (fd *FD) Fchmod(mode uint32) error {
34-
if err := fd.incref(); err != nil {
35-
return err
36-
}
37-
defer fd.decref()
38-
return ignoringEINTR(func() error {
39-
return syscall.Fchmod(fd.Sysfd, mode)
40-
})
41-
}
42-
4332
// Fchown wraps syscall.Fchown.
4433
func (fd *FD) Fchown(uid, gid int) error {
4534
if err := fd.incref(); err != nil {

src/internal/poll/fd_unix.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,17 @@ func (fd *FD) ReadDirent(buf []byte) (int, error) {
437437
}
438438
}
439439

440+
// Fchmod wraps syscall.Fchmod.
441+
func (fd *FD) Fchmod(mode uint32) error {
442+
if err := fd.incref(); err != nil {
443+
return err
444+
}
445+
defer fd.decref()
446+
return ignoringEINTR(func() error {
447+
return syscall.Fchmod(fd.Sysfd, mode)
448+
})
449+
}
450+
440451
// Fchdir wraps syscall.Fchdir.
441452
func (fd *FD) Fchdir() error {
442453
if err := fd.incref(); err != nil {

src/internal/poll/fd_windows.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,33 @@ func (fd *FD) FindNextFile(data *syscall.Win32finddata) error {
886886
return syscall.FindNextFile(fd.Sysfd, data)
887887
}
888888

889+
// Fchmod updates syscall.ByHandleFileInformation.Fileattributes when needed.
890+
func (fd *FD) Fchmod(mode uint32) error {
891+
if err := fd.incref(); err != nil {
892+
return err
893+
}
894+
defer fd.decref()
895+
896+
var d syscall.ByHandleFileInformation
897+
if err := syscall.GetFileInformationByHandle(fd.Sysfd, &d); err != nil {
898+
return err
899+
}
900+
attrs := d.FileAttributes
901+
if mode&syscall.S_IWRITE != 0 {
902+
attrs &^= syscall.FILE_ATTRIBUTE_READONLY
903+
} else {
904+
attrs |= syscall.FILE_ATTRIBUTE_READONLY
905+
}
906+
if attrs == d.FileAttributes {
907+
return nil
908+
}
909+
910+
var du windows.FILE_BASIC_INFO
911+
du.FileAttributes = attrs
912+
l := uint32(unsafe.Sizeof(d))
913+
return windows.SetFileInformationByHandle(fd.Sysfd, windows.FileBasicInfo, uintptr(unsafe.Pointer(&du)), l)
914+
}
915+
889916
// Fchdir wraps syscall.Fchdir.
890917
func (fd *FD) Fchdir() error {
891918
if err := fd.incref(); err != nil {

src/internal/syscall/windows/syscall_windows.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,14 @@ type IpAdapterAddresses struct {
131131
/* more fields might be present here. */
132132
}
133133

134+
type FILE_BASIC_INFO struct {
135+
CreationTime syscall.Filetime
136+
LastAccessTime syscall.Filetime
137+
LastWriteTime syscall.Filetime
138+
ChangedTime syscall.Filetime
139+
FileAttributes uint32
140+
}
141+
134142
const (
135143
IfOperStatusUp = 1
136144
IfOperStatusDown = 2
@@ -145,6 +153,7 @@ const (
145153
//sys GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
146154
//sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW
147155
//sys GetModuleFileName(module syscall.Handle, fn *uint16, len uint32) (n uint32, err error) = kernel32.GetModuleFileNameW
156+
//sys SetFileInformationByHandle(handle syscall.Handle, fileInformationClass uint32, buf uintptr, bufsize uint32) (err error) = kernel32.SetFileInformationByHandle
148157

149158
const (
150159
WSA_FLAG_OVERLAPPED = 0x01

src/internal/syscall/windows/zsyscall_windows.go

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

src/os/os_test.go

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,29 +1099,34 @@ func checkMode(t *testing.T, path string, mode FileMode) {
10991099
if err != nil {
11001100
t.Fatalf("Stat %q (looking for mode %#o): %s", path, mode, err)
11011101
}
1102-
if dir.Mode()&0777 != mode {
1102+
if dir.Mode()&ModePerm != mode {
11031103
t.Errorf("Stat %q: mode %#o want %#o", path, dir.Mode(), mode)
11041104
}
11051105
}
11061106

11071107
func TestChmod(t *testing.T) {
1108-
// Chmod is not supported under windows.
1109-
if runtime.GOOS == "windows" {
1110-
return
1111-
}
11121108
f := newFile("TestChmod", t)
11131109
defer Remove(f.Name())
11141110
defer f.Close()
1111+
// Creation mode is read write
11151112

1116-
if err := Chmod(f.Name(), 0456); err != nil {
1117-
t.Fatalf("chmod %s 0456: %s", f.Name(), err)
1113+
fm := FileMode(0456)
1114+
if runtime.GOOS == "windows" {
1115+
fm = FileMode(0444) // read-only file
11181116
}
1119-
checkMode(t, f.Name(), 0456)
1117+
if err := Chmod(f.Name(), fm); err != nil {
1118+
t.Fatalf("chmod %s %#o: %s", f.Name(), fm, err)
1119+
}
1120+
checkMode(t, f.Name(), fm)
11201121

1121-
if err := f.Chmod(0123); err != nil {
1122-
t.Fatalf("chmod %s 0123: %s", f.Name(), err)
1122+
fm = FileMode(0123)
1123+
if runtime.GOOS == "windows" {
1124+
fm = FileMode(0666) // read-write file
1125+
}
1126+
if err := f.Chmod(fm); err != nil {
1127+
t.Fatalf("chmod %s %#o: %s", f.Name(), fm, err)
11231128
}
1124-
checkMode(t, f.Name(), 0123)
1129+
checkMode(t, f.Name(), fm)
11251130
}
11261131

11271132
func checkSize(t *testing.T, f *File, size int64) {

0 commit comments

Comments
 (0)