mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
feat: Implement Lchown function for changing file ownership (#5161)
* feat: Implement Lchown function for changing file ownership - Added Lchown function to change the numeric uid and gid of a file or symbolic link. - Included error handling to return *PathError for failed operations. - Added unit tests for Lchown to verify behavior on different error scenarios. * fix: fix chmod tests
This commit is contained in:
@@ -166,6 +166,19 @@ func Chown(name string, uid, gid int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Lchown 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 itself.
|
||||
// If there is an error, it will be of type [*PathError].
|
||||
//
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func Lchown(name string, uid, gid int) error {
|
||||
e := ignoringEINTR(func() error { return syscall.Lchown(name, uid, gid) })
|
||||
if e != nil {
|
||||
return &PathError{Op: "lchown", 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.
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"errors"
|
||||
"io/fs"
|
||||
. "os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
@@ -70,3 +71,38 @@ func TestChownErr(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLchownErr(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("TestLchown", t)
|
||||
defer Remove(f.Name())
|
||||
defer f.Close()
|
||||
link := filepath.Join(TempDir(), "TestLchownLink")
|
||||
_ = Symlink(f.Name(), link)
|
||||
defer Remove(link)
|
||||
|
||||
// EACCES
|
||||
if err := Lchown(link, TEST_UID_ROOT, TEST_GID_ROOT); err != nil {
|
||||
errCmp := fs.PathError{Op: "lchown", Path: link, Err: errors.New("operation not permitted")}
|
||||
if errors.Is(err, &errCmp) {
|
||||
t.Fatalf("lchown(%s, uid=%v, gid=%v): got '%v', want 'operation not permitted'", link, TEST_UID_ROOT, TEST_GID_ROOT, err)
|
||||
}
|
||||
}
|
||||
|
||||
// ENOENT
|
||||
if err := Chown("invalid", Geteuid(), Getgid()); err != nil {
|
||||
errCmp := fs.PathError{Op: "lchown", 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'", link, Geteuid(), Getegid(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,6 +172,15 @@ func Chown(path string, uid, gid int) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func Lchown(path string, uid, gid int) (err error) {
|
||||
data := cstring(path)
|
||||
fail := int(libc_lchown(&data[0], uid, gid))
|
||||
if fail < 0 {
|
||||
err = getErrno()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Fork() (err error) {
|
||||
fail := int(libc_fork())
|
||||
if fail < 0 {
|
||||
@@ -368,6 +377,11 @@ func libc_chmod(pathname *byte, mode uint32) int32
|
||||
//export chown
|
||||
func libc_chown(pathname *byte, owner, group int) int32
|
||||
|
||||
// int lchown(const char *pathname, uid_t owner, gid_t group);
|
||||
//
|
||||
//export lchown
|
||||
func libc_lchown(pathname *byte, owner, group int) int32
|
||||
|
||||
// int mkdir(const char *pathname, mode_t mode);
|
||||
//
|
||||
//export mkdir
|
||||
|
||||
Reference in New Issue
Block a user