Skip to content

Commit 724b52c

Browse files
committed
add os.Chown
Signed-off-by: leongross <[email protected]>
1 parent a5ceb79 commit 724b52c

File tree

3 files changed

+55
-0
lines changed

3 files changed

+55
-0
lines changed

src/os/file_anyos.go

+17
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,23 @@ func Chmod(name string, mode FileMode) error {
147147
return nil
148148
}
149149

150+
// Chown changes the numeric uid and gid of the named file.
151+
// If the file is a symbolic link, it changes the uid and gid of the link's target.
152+
// A uid or gid of -1 means to not change that value.
153+
// If there is an error, it will be of type *PathError.
154+
//
155+
// On Windows or Plan 9, Chown always returns the syscall.EWINDOWS or
156+
// EPLAN9 error, wrapped in *PathError.
157+
func Chown(name string, uid, gid int) error {
158+
e := ignoringEINTR(func() error {
159+
return syscall.Chown(name, uid, gid)
160+
})
161+
if e != nil {
162+
return &PathError{Op: "chown", Path: name, Err: e}
163+
}
164+
return nil
165+
}
166+
150167
// ignoringEINTR makes a function call and repeats it if it returns an
151168
// EINTR error. This appears to be required even though we install all
152169
// signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846.

src/os/os_chmod_test.go

+24
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ package os_test
1111
import (
1212
. "os"
1313
"runtime"
14+
"syscall"
1415
"testing"
1516
)
1617

1718
func TestChmod(t *testing.T) {
19+
// Chmod
1820
f := newFile("TestChmod", t)
1921
defer Remove(f.Name())
2022
defer f.Close()
@@ -28,4 +30,26 @@ func TestChmod(t *testing.T) {
2830
t.Fatalf("chmod %s %#o: %s", f.Name(), fm, err)
2931
}
3032
checkMode(t, f.Name(), fm)
33+
34+
}
35+
36+
func TestChown(t *testing.T) {
37+
f := newFile("TestChown", t)
38+
defer Remove(f.Name())
39+
defer f.Close()
40+
41+
if runtime.GOOS != "windows" {
42+
if err := Chown(f.Name(), 0, 0); err != nil {
43+
t.Fatalf("chown %s 0 0: %s", f.Name(), err)
44+
}
45+
46+
fi, err := Stat(f.Name())
47+
if err != nil {
48+
t.Fatalf("stat %s: %s", f.Name(), err)
49+
}
50+
51+
if fi.Sys().(*syscall.Stat_t).Uid != 0 || fi.Sys().(*syscall.Stat_t).Gid != 0 {
52+
t.Fatalf("chown %s 0 0: uid=%d gid=%d", f.Name(), fi.Sys().(*syscall.Stat_t).Uid, fi.Sys().(*syscall.Stat_t).Gid)
53+
}
54+
}
3155
}

src/syscall/syscall_libc.go

+14
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,15 @@ func Unlink(path string) (err error) {
153153
return
154154
}
155155

156+
func Chown(path string, uid, gid int) (err error) {
157+
data := cstring(path)
158+
fail := int(libc_chown(&data[0], uid, gid))
159+
if fail < 0 {
160+
err = getErrno()
161+
}
162+
return
163+
}
164+
156165
func Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
157166

158167
func Kill(pid int, sig Signal) (err error) {
@@ -396,6 +405,11 @@ func libc_chdir(pathname *byte) int32
396405
//export chmod
397406
func libc_chmod(pathname *byte, mode uint32) int32
398407

408+
// int chown(const char *pathname, uid_t owner, gid_t group);
409+
//
410+
//export chown
411+
func libc_chown(pathname *byte, owner, group int) int32
412+
399413
// int mkdir(const char *pathname, mode_t mode);
400414
//
401415
//export mkdir

0 commit comments

Comments
 (0)