| // Copyright 2025 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| //go:build unix || (js && wasm) || wasip1 | |
| package os_test | |
| import ( | |
| "fmt" | |
| "os" | |
| "path/filepath" | |
| "runtime" | |
| "syscall" | |
| "testing" | |
| ) | |
| func TestRootChown(t *testing.T) { | |
| if runtime.GOOS == "wasip1" { | |
| t.Skip("Chown 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.Fatal(err) | |
| } | |
| groups = append(groups, os.Getgid()) | |
| for _, test := range rootTestCases { | |
| test.run(t, func(t *testing.T, target string, root *os.Root) { | |
| if target != "" { | |
| if err := os.WriteFile(target, nil, 0o666); err != nil { | |
| t.Fatal(err) | |
| } | |
| } | |
| for _, gid := range groups { | |
| err := root.Chown(test.open, -1, gid) | |
| if errEndsTest(t, err, test.wantError, "root.Chown(%q, -1, %v)", test.open, gid) { | |
| return | |
| } | |
| checkUidGid(t, target, int(sys.Uid), gid) | |
| } | |
| }) | |
| } | |
| } | |
| 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.Fatal(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) | |
| } | |
| groups, err := os.Getgroups() | |
| if err != nil { | |
| t.Fatal(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) { | |
| chown := os.Chown | |
| lstat := os.Lstat | |
| if r != nil { | |
| chown = r.Chown | |
| lstat = r.Lstat | |
| } | |
| err := chown(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 | |
| }) | |
| } | |
| } | |
| 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.Fatal(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 | |
| }) | |
| } | |
| } |