mirror of
https://github.com/golang/go.git
synced 2025-05-05 23:53:05 +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) Chmod(string, fs.FileMode) error #67002
|
||||||
pkg os, method (*Root) Chown(string, int, int) 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) 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.Chmod]
|
||||||
* [os.Root.Chown]
|
* [os.Root.Chown]
|
||||||
* [os.Root.Chtimes]
|
* [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)
|
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.
|
// Chtimes changes the access and modification times of the named file in the root.
|
||||||
// See [Chtimes] for more details.
|
// See [Chtimes] for more details.
|
||||||
func (r *Root) Chtimes(name string, atime time.Time, mtime time.Time) error {
|
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
|
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 {
|
func rootChtimes(r *Root, name string, atime time.Time, mtime time.Time) error {
|
||||||
if err := checkPathEscapes(r, name); err != nil {
|
if err := checkPathEscapes(r, name); err != nil {
|
||||||
return &PathError{Op: "chtimesat", Path: name, Err: err}
|
return &PathError{Op: "chtimesat", Path: name, Err: err}
|
||||||
|
@ -88,6 +88,16 @@ func rootChown(r *Root, name string, uid, gid int) error {
|
|||||||
return nil
|
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 {
|
func rootChtimes(r *Root, name string, atime time.Time, mtime time.Time) error {
|
||||||
_, err := doInRoot(r, name, func(parent sysfdType, name string) (struct{}, error) {
|
_, err := doInRoot(r, name, func(parent sysfdType, name string) (struct{}, error) {
|
||||||
return struct{}{}, chtimesat(parent, name, atime, mtime)
|
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 {
|
func chtimesat(parent int, name string, atime time.Time, mtime time.Time) error {
|
||||||
return afterResolvingSymlink(parent, name, func() error {
|
return afterResolvingSymlink(parent, name, func() error {
|
||||||
return ignoringEINTR(func() error {
|
return ignoringEINTR(func() error {
|
||||||
|
@ -9,6 +9,7 @@ package os_test
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"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) {
|
func TestRootConsistencyChown(t *testing.T) {
|
||||||
if runtime.GOOS == "wasip1" {
|
if runtime.GOOS == "wasip1" {
|
||||||
t.Skip("Chown not supported on " + runtime.GOOS)
|
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
|
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 {
|
func mkdirat(dirfd syscall.Handle, name string, perm FileMode) error {
|
||||||
return windows.Mkdirat(dirfd, name, syscallMode(perm))
|
return windows.Mkdirat(dirfd, name, syscallMode(perm))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user