mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
os: add Root.Lchown
For #67002 Change-Id: I1bbf18838a1dd2281a2b6e56fc8a58ef70007adc Reviewed-on: https://go-review.googlesource.com/c/go/+/649536 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Damien Neil <dneil@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com>
This commit is contained in:
parent
f9f5d1e844
commit
1eb1579fba
@ -1,3 +1,4 @@
|
||||
pkg os, method (*Root) Chmod(string, fs.FileMode) error #67002
|
||||
pkg os, method (*Root) Chown(string, int, int) error #67002
|
||||
pkg os, method (*Root) Chtimes(string, time.Time, time.Time) error #67002
|
||||
pkg os, method (*Root) Lchown(string, int, int) error #67002
|
||||
|
@ -3,3 +3,4 @@ The [os.Root] type supports the following additional methods:
|
||||
* [os.Root.Chmod]
|
||||
* [os.Root.Chown]
|
||||
* [os.Root.Chtimes]
|
||||
* [os.Root.Lchown]
|
||||
|
@ -159,6 +159,12 @@ func (r *Root) Chown(name string, uid, gid int) error {
|
||||
return rootChown(r, name, uid, gid)
|
||||
}
|
||||
|
||||
// Lchown changes the numeric uid and gid of the named file in the root.
|
||||
// See [Lchown] for more details.
|
||||
func (r *Root) Lchown(name string, uid, gid int) error {
|
||||
return rootLchown(r, name, uid, gid)
|
||||
}
|
||||
|
||||
// Chtimes changes the access and modification times of the named file in the root.
|
||||
// See [Chtimes] for more details.
|
||||
func (r *Root) Chtimes(name string, atime time.Time, mtime time.Time) error {
|
||||
|
@ -116,6 +116,16 @@ func rootChown(r *Root, name string, uid, gid int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func rootLchown(r *Root, name string, uid, gid int) error {
|
||||
if err := checkPathEscapesLstat(r, name); err != nil {
|
||||
return &PathError{Op: "lchownat", Path: name, Err: err}
|
||||
}
|
||||
if err := Lchown(joinPath(r.root.name, name), uid, gid); err != nil {
|
||||
return &PathError{Op: "lchownat", Path: name, Err: underlyingError(err)}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func rootChtimes(r *Root, name string, atime time.Time, mtime time.Time) error {
|
||||
if err := checkPathEscapes(r, name); err != nil {
|
||||
return &PathError{Op: "chtimesat", Path: name, Err: err}
|
||||
|
@ -88,6 +88,16 @@ func rootChown(r *Root, name string, uid, gid int) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func rootLchown(r *Root, name string, uid, gid int) error {
|
||||
_, err := doInRoot(r, name, func(parent sysfdType, name string) (struct{}, error) {
|
||||
return struct{}{}, lchownat(parent, name, uid, gid)
|
||||
})
|
||||
if err != nil {
|
||||
return &PathError{Op: "lchownat", Path: name, Err: err}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func rootChtimes(r *Root, name string, atime time.Time, mtime time.Time) error {
|
||||
_, err := doInRoot(r, name, func(parent sysfdType, name string) (struct{}, error) {
|
||||
return struct{}{}, chtimesat(parent, name, atime, mtime)
|
||||
|
@ -166,6 +166,12 @@ func chownat(parent int, name string, uid, gid int) error {
|
||||
})
|
||||
}
|
||||
|
||||
func lchownat(parent int, name string, uid, gid int) error {
|
||||
return ignoringEINTR(func() error {
|
||||
return unix.Fchownat(parent, name, uid, gid, unix.AT_SYMLINK_NOFOLLOW)
|
||||
})
|
||||
}
|
||||
|
||||
func chtimesat(parent int, name string, atime time.Time, mtime time.Time) error {
|
||||
return afterResolvingSymlink(parent, name, func() error {
|
||||
return ignoringEINTR(func() error {
|
||||
|
@ -9,6 +9,7 @@ package os_test
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
@ -50,6 +51,46 @@ func TestRootChown(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRootLchown(t *testing.T) {
|
||||
if runtime.GOOS == "wasip1" {
|
||||
t.Skip("Lchown not supported on " + runtime.GOOS)
|
||||
}
|
||||
|
||||
// Look up the current default uid/gid.
|
||||
f := newFile(t)
|
||||
dir, err := f.Stat()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sys := dir.Sys().(*syscall.Stat_t)
|
||||
|
||||
groups, err := os.Getgroups()
|
||||
if err != nil {
|
||||
t.Fatalf("getgroups: %v", err)
|
||||
}
|
||||
groups = append(groups, os.Getgid())
|
||||
for _, test := range rootTestCases {
|
||||
test.run(t, func(t *testing.T, target string, root *os.Root) {
|
||||
wantError := test.wantError
|
||||
if test.ltarget != "" {
|
||||
wantError = false
|
||||
target = filepath.Join(root.Name(), test.ltarget)
|
||||
} else if target != "" {
|
||||
if err := os.WriteFile(target, nil, 0o666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
for _, gid := range groups {
|
||||
err := root.Lchown(test.open, -1, gid)
|
||||
if errEndsTest(t, err, wantError, "root.Lchown(%q, -1, %v)", test.open, gid) {
|
||||
return
|
||||
}
|
||||
checkUidGid(t, target, int(sys.Uid), gid)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRootConsistencyChown(t *testing.T) {
|
||||
if runtime.GOOS == "wasip1" {
|
||||
t.Skip("Chown not supported on " + runtime.GOOS)
|
||||
@ -85,3 +126,39 @@ func TestRootConsistencyChown(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRootConsistencyLchown(t *testing.T) {
|
||||
if runtime.GOOS == "wasip1" {
|
||||
t.Skip("Lchown not supported on " + runtime.GOOS)
|
||||
}
|
||||
groups, err := os.Getgroups()
|
||||
if err != nil {
|
||||
t.Fatalf("getgroups: %v", err)
|
||||
}
|
||||
var gid int
|
||||
if len(groups) == 0 {
|
||||
gid = os.Getgid()
|
||||
} else {
|
||||
gid = groups[0]
|
||||
}
|
||||
for _, test := range rootConsistencyTestCases {
|
||||
test.run(t, func(t *testing.T, path string, r *os.Root) (string, error) {
|
||||
lchown := os.Lchown
|
||||
lstat := os.Lstat
|
||||
if r != nil {
|
||||
lchown = r.Lchown
|
||||
lstat = r.Lstat
|
||||
}
|
||||
err := lchown(path, -1, gid)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fi, err := lstat(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
sys := fi.Sys().(*syscall.Stat_t)
|
||||
return fmt.Sprintf("%v %v", sys.Uid, sys.Gid), nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -281,6 +281,10 @@ func chownat(parent syscall.Handle, name string, uid, gid int) error {
|
||||
return syscall.EWINDOWS // matches syscall.Chown
|
||||
}
|
||||
|
||||
func lchownat(parent syscall.Handle, name string, uid, gid int) error {
|
||||
return syscall.EWINDOWS // matches syscall.Lchown
|
||||
}
|
||||
|
||||
func mkdirat(dirfd syscall.Handle, name string, perm FileMode) error {
|
||||
return windows.Mkdirat(dirfd, name, syscallMode(perm))
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user