mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-04 02:57:46 +00:00
@@ -147,6 +147,20 @@ func Chmod(name string, mode FileMode) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Chown changes the numeric uid and gid of the named file.
|
||||
// If the file is a symbolic link, it changes the uid and gid of the link's target.
|
||||
// A uid or gid of -1 means to not change that value.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func Chown(name string, uid, gid int) error {
|
||||
e := ignoringEINTR(func() error {
|
||||
return syscall.Chown(name, uid, gid)
|
||||
})
|
||||
if e != nil {
|
||||
return &PathError{Op: "chown", Path: name, Err: e}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ignoringEINTR makes a function call and repeats it if it returns an
|
||||
// EINTR error. This appears to be required even though we install all
|
||||
// signal handlers with SA_RESTART: see #22838, #38033, #38836, #40846.
|
||||
|
||||
@@ -9,12 +9,15 @@
|
||||
package os_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
. "os"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestChmod(t *testing.T) {
|
||||
// Chmod
|
||||
f := newFile("TestChmod", t)
|
||||
defer Remove(f.Name())
|
||||
defer f.Close()
|
||||
@@ -28,4 +31,42 @@ func TestChmod(t *testing.T) {
|
||||
t.Fatalf("chmod %s %#o: %s", f.Name(), fm, err)
|
||||
}
|
||||
checkMode(t, f.Name(), fm)
|
||||
|
||||
}
|
||||
|
||||
// Since testing syscalls requires a static, predictable environment that has to be controlled
|
||||
// by the CI, we don't test for success but for failures and verify that the error messages are as expected.
|
||||
// EACCES is returned when the user does not have the required permissions to change the ownership of the file
|
||||
// ENOENT is returned when the file does not exist
|
||||
// ENOTDIR is returned when the file is not a directory
|
||||
func TestChownErr(t *testing.T) {
|
||||
if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
|
||||
t.Log("skipping on " + runtime.GOOS)
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
TEST_UID_ROOT = 0
|
||||
TEST_GID_ROOT = 0
|
||||
)
|
||||
|
||||
f := newFile("TestChown", t)
|
||||
defer Remove(f.Name())
|
||||
defer f.Close()
|
||||
|
||||
// EACCES
|
||||
if err := Chown(f.Name(), TEST_UID_ROOT, TEST_GID_ROOT); err != nil {
|
||||
errCmp := fs.PathError{Op: "chown", Path: f.Name(), Err: errors.New("operation not permitted")}
|
||||
if errors.Is(err, &errCmp) {
|
||||
t.Fatalf("chown(%s, uid=%v, gid=%v): got '%v', want 'operation not permitted'", f.Name(), TEST_UID_ROOT, TEST_GID_ROOT, err)
|
||||
}
|
||||
}
|
||||
|
||||
// ENOENT
|
||||
if err := Chown("invalid", Geteuid(), Getgid()); err != nil {
|
||||
errCmp := fs.PathError{Op: "chown", Path: "invalid", Err: errors.New("no such file or directory")}
|
||||
if errors.Is(err, &errCmp) {
|
||||
t.Fatalf("chown(%s, uid=%v, gid=%v): got '%v', want 'no such file or directory'", f.Name(), Geteuid(), Getegid(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,6 +163,15 @@ func Unlink(path string) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func Chown(path string, uid, gid int) (err error) {
|
||||
data := cstring(path)
|
||||
fail := int(libc_chown(&data[0], uid, gid))
|
||||
if fail < 0 {
|
||||
err = getErrno()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
|
||||
|
||||
func Kill(pid int, sig Signal) (err error) {
|
||||
@@ -357,6 +366,11 @@ func libc_chdir(pathname *byte) int32
|
||||
//export chmod
|
||||
func libc_chmod(pathname *byte, mode uint32) int32
|
||||
|
||||
// int chown(const char *pathname, uid_t owner, gid_t group);
|
||||
//
|
||||
//export chown
|
||||
func libc_chown(pathname *byte, owner, group int) int32
|
||||
|
||||
// int mkdir(const char *pathname, mode_t mode);
|
||||
//
|
||||
//export mkdir
|
||||
|
||||
Reference in New Issue
Block a user