aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/os
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2019-01-18 19:04:36 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-01-18 19:04:36 +0000
commit4f4a855d82a889cebcfca150a7a43909bcb6a346 (patch)
treef12bae0781920fa34669fe30b6f4615a86d9fb80 /libgo/go/os
parent225220d668dafb8262db7012bced688acbe63b33 (diff)
downloadgcc-4f4a855d82a889cebcfca150a7a43909bcb6a346.zip
gcc-4f4a855d82a889cebcfca150a7a43909bcb6a346.tar.gz
gcc-4f4a855d82a889cebcfca150a7a43909bcb6a346.tar.bz2
libgo: update to Go1.12beta2
Reviewed-on: https://go-review.googlesource.com/c/158019 gotools/: * Makefile.am (go_cmd_vet_files): Update for Go1.12beta2 release. (GOTOOLS_TEST_TIMEOUT): Increase to 600. (check-runtime): Export LD_LIBRARY_PATH before computing GOARCH and GOOS. (check-vet): Copy golang.org/x/tools into check-vet-dir. * Makefile.in: Regenerate. gcc/testsuite/: * go.go-torture/execute/names-1.go: Stop using debug/xcoff, which is no longer externally visible. From-SVN: r268084
Diffstat (limited to 'libgo/go/os')
-rw-r--r--libgo/go/os/dir_gccgo.go7
-rw-r--r--libgo/go/os/dir_ios.go87
-rw-r--r--libgo/go/os/dir_libc64_gccgo.go3
-rw-r--r--libgo/go/os/dir_libc_gccgo.go3
-rw-r--r--libgo/go/os/dir_unix.go38
-rw-r--r--libgo/go/os/env_unix_test.go2
-rw-r--r--libgo/go/os/error_posix.go2
-rw-r--r--libgo/go/os/error_unix_test.go2
-rw-r--r--libgo/go/os/example_test.go36
-rw-r--r--libgo/go/os/exec/exec.go9
-rw-r--r--libgo/go/os/exec/exec_posix_test.go2
-rw-r--r--libgo/go/os/exec/exec_test.go62
-rw-r--r--libgo/go/os/exec/lp_unix_test.go2
-rw-r--r--libgo/go/os/exec_plan9.go10
-rw-r--r--libgo/go/os/exec_posix.go19
-rw-r--r--libgo/go/os/exec_windows.go3
-rw-r--r--libgo/go/os/executable_test.go4
-rw-r--r--libgo/go/os/file.go36
-rw-r--r--libgo/go/os/file_plan9.go18
-rw-r--r--libgo/go/os/file_posix.go3
-rw-r--r--libgo/go/os/file_unix.go84
-rw-r--r--libgo/go/os/os_test.go73
-rw-r--r--libgo/go/os/os_unix_test.go7
-rw-r--r--libgo/go/os/path.go102
-rw-r--r--libgo/go/os/path_test.go125
-rw-r--r--libgo/go/os/path_unix.go28
-rw-r--r--libgo/go/os/path_windows_test.go6
-rw-r--r--libgo/go/os/pipe_test.go2
-rw-r--r--libgo/go/os/rawconn.go47
-rw-r--r--libgo/go/os/rawconn_test.go65
-rw-r--r--libgo/go/os/removeall_at.go138
-rw-r--r--libgo/go/os/removeall_noat.go123
-rw-r--r--libgo/go/os/removeall_test.go294
-rw-r--r--libgo/go/os/signal/internal/pty/pty.go1
-rw-r--r--libgo/go/os/signal/signal_cgo_test.go5
-rw-r--r--libgo/go/os/stat_aix.go2
-rw-r--r--libgo/go/os/stat_test.go292
-rw-r--r--libgo/go/os/sticky_bsd.go2
-rw-r--r--libgo/go/os/sticky_notbsd.go1
-rw-r--r--libgo/go/os/sys_aix.go26
-rw-r--r--libgo/go/os/types.go2
-rw-r--r--libgo/go/os/types_windows.go85
-rw-r--r--libgo/go/os/user/lookup.go4
-rw-r--r--libgo/go/os/user/lookup_stubs.go15
-rw-r--r--libgo/go/os/user/lookup_unix.go2
-rw-r--r--libgo/go/os/user/lookup_unix_test.go2
-rw-r--r--libgo/go/os/user/user.go2
-rw-r--r--libgo/go/os/user/user_test.go18
-rw-r--r--libgo/go/os/wait_unimp.go2
-rw-r--r--libgo/go/os/wait_wait6.go2
-rw-r--r--libgo/go/os/wait_waitid.go2
51 files changed, 1443 insertions, 464 deletions
diff --git a/libgo/go/os/dir_gccgo.go b/libgo/go/os/dir_gccgo.go
index f660646..60f70aa 100644
--- a/libgo/go/os/dir_gccgo.go
+++ b/libgo/go/os/dir_gccgo.go
@@ -16,6 +16,9 @@ import (
//extern pathconf
func libc_pathconf(*byte, int) int
+//extern fdopendir
+func libc_fdopendir(int32) *syscall.DIR
+
func clen(n []byte) int {
for i := 0; i < len(n); i++ {
if n[i] == 0 {
@@ -48,11 +51,11 @@ func (file *File) readdirnames(n int) (names []string, err error) {
}
syscall.Entersyscall()
- r := libc_opendir(p)
+ r := libc_fdopendir(int32(file.pfd.Sysfd))
errno := syscall.GetErrno()
syscall.Exitsyscall()
if r == nil {
- return nil, &PathError{"opendir", file.name, errno}
+ return nil, &PathError{"fdopendir", file.name, errno}
}
file.dirinfo = new(dirInfo)
diff --git a/libgo/go/os/dir_ios.go b/libgo/go/os/dir_ios.go
new file mode 100644
index 0000000..8c14d89
--- /dev/null
+++ b/libgo/go/os/dir_ios.go
@@ -0,0 +1,87 @@
+// Copyright 2009 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.
+
+// +build darwin
+// +build arm arm64
+
+package os
+
+import (
+ "io"
+ "runtime"
+ "syscall"
+ "unsafe"
+)
+
+// Auxiliary information if the File describes a directory
+type dirInfo struct {
+ dir uintptr // Pointer to DIR structure from dirent.h
+}
+
+func (d *dirInfo) close() {
+ if d.dir == 0 {
+ return
+ }
+ closedir(d.dir)
+ d.dir = 0
+}
+
+func (f *File) readdirnames(n int) (names []string, err error) {
+ if f.dirinfo == nil {
+ dir, call, errno := f.pfd.OpenDir()
+ if errno != nil {
+ return nil, wrapSyscallError(call, errno)
+ }
+ f.dirinfo = &dirInfo{
+ dir: dir,
+ }
+ }
+ d := f.dirinfo
+
+ size := n
+ if size <= 0 {
+ size = 100
+ n = -1
+ }
+
+ names = make([]string, 0, size)
+ var dirent syscall.Dirent
+ var entptr uintptr
+ for len(names) < size {
+ if res := readdir_r(d.dir, uintptr(unsafe.Pointer(&dirent)), uintptr(unsafe.Pointer(&entptr))); res != 0 {
+ return names, wrapSyscallError("readdir", syscall.Errno(res))
+ }
+ if entptr == 0 { // EOF
+ break
+ }
+ if dirent.Ino == 0 {
+ continue
+ }
+ name := (*[len(syscall.Dirent{}.Name)]byte)(unsafe.Pointer(&dirent.Name))[:]
+ for i, c := range name {
+ if c == 0 {
+ name = name[:i]
+ break
+ }
+ }
+ // Check for useless names before allocating a string.
+ if string(name) == "." || string(name) == ".." {
+ continue
+ }
+ names = append(names, string(name))
+ runtime.KeepAlive(f)
+ }
+ if n >= 0 && len(names) == 0 {
+ return names, io.EOF
+ }
+ return names, nil
+}
+
+// Implemented in syscall/syscall_darwin.go.
+
+//go:linkname closedir syscall.closedir
+func closedir(dir uintptr) (err error)
+
+//go:linkname readdir_r syscall.readdir_r
+func readdir_r(dir, entry, result uintptr) (res int)
diff --git a/libgo/go/os/dir_libc64_gccgo.go b/libgo/go/os/dir_libc64_gccgo.go
index 95d4663..dc3ba7f 100644
--- a/libgo/go/os/dir_libc64_gccgo.go
+++ b/libgo/go/os/dir_libc64_gccgo.go
@@ -8,8 +8,5 @@ package os
import "syscall"
-//extern opendir64
-func libc_opendir(*byte) *syscall.DIR
-
//extern closedir64
func libc_closedir(*syscall.DIR) int
diff --git a/libgo/go/os/dir_libc_gccgo.go b/libgo/go/os/dir_libc_gccgo.go
index 1ee253c..b46eb4c 100644
--- a/libgo/go/os/dir_libc_gccgo.go
+++ b/libgo/go/os/dir_libc_gccgo.go
@@ -8,8 +8,5 @@ package os
import "syscall"
-//extern opendir
-func libc_opendir(*byte) *syscall.DIR
-
//extern closedir
func libc_closedir(*syscall.DIR) int
diff --git a/libgo/go/os/dir_unix.go b/libgo/go/os/dir_unix.go
deleted file mode 100644
index edfc9ea..0000000
--- a/libgo/go/os/dir_unix.go
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2009 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.
-
-// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
-
-package os
-
-import (
- "io"
-)
-
-func (f *File) readdir(n int) (fi []FileInfo, err error) {
- dirname := f.name
- if dirname == "" {
- dirname = "."
- }
- names, err := f.Readdirnames(n)
- fi = make([]FileInfo, 0, len(names))
- for _, filename := range names {
- fip, lerr := lstat(dirname + "/" + filename)
- if IsNotExist(lerr) {
- // File disappeared between readdir + stat.
- // Just treat it as if it didn't exist.
- continue
- }
- if lerr != nil {
- return fi, lerr
- }
- fi = append(fi, fip)
- }
- if len(fi) == 0 && err == nil && n > 0 {
- // Per File.Readdir, the slice must be non-empty or err
- // must be non-nil if n > 0.
- err = io.EOF
- }
- return fi, err
-}
diff --git a/libgo/go/os/env_unix_test.go b/libgo/go/os/env_unix_test.go
index f7b67eb..89430b3 100644
--- a/libgo/go/os/env_unix_test.go
+++ b/libgo/go/os/env_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package os_test
diff --git a/libgo/go/os/error_posix.go b/libgo/go/os/error_posix.go
index 3c81b41..0478ba6 100644
--- a/libgo/go/os/error_posix.go
+++ b/libgo/go/os/error_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
package os
diff --git a/libgo/go/os/error_unix_test.go b/libgo/go/os/error_unix_test.go
index 8db9867..c47af56 100644
--- a/libgo/go/os/error_unix_test.go
+++ b/libgo/go/os/error_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
package os_test
diff --git a/libgo/go/os/example_test.go b/libgo/go/os/example_test.go
index e21415a..8b6566e 100644
--- a/libgo/go/os/example_test.go
+++ b/libgo/go/os/example_test.go
@@ -55,6 +55,7 @@ func ExampleFileMode() {
log.Fatal(err)
}
+ fmt.Printf("permissions: %#o\n", fi.Mode().Perm()) // 0400, 0777, etc.
switch mode := fi.Mode(); {
case mode.IsRegular():
fmt.Println("regular file")
@@ -70,38 +71,35 @@ func ExampleFileMode() {
func ExampleIsNotExist() {
filename := "a-nonexistent-file"
if _, err := os.Stat(filename); os.IsNotExist(err) {
- fmt.Printf("file does not exist")
+ fmt.Println("file does not exist")
}
// Output:
// file does not exist
}
-func init() {
- os.Setenv("USER", "gopher")
- os.Setenv("HOME", "/usr/gopher")
- os.Unsetenv("GOPATH")
-}
-
func ExampleExpand() {
mapper := func(placeholderName string) string {
switch placeholderName {
case "DAY_PART":
return "morning"
- case "USER":
+ case "NAME":
return "Gopher"
}
return ""
}
- fmt.Println(os.Expand("Good ${DAY_PART}, $USER!", mapper))
+ fmt.Println(os.Expand("Good ${DAY_PART}, $NAME!", mapper))
// Output:
// Good morning, Gopher!
}
func ExampleExpandEnv() {
- fmt.Println(os.ExpandEnv("$USER lives in ${HOME}."))
+ os.Setenv("NAME", "gopher")
+ os.Setenv("BURROW", "/usr/gopher")
+
+ fmt.Println(os.ExpandEnv("$NAME lives in ${BURROW}."))
// Output:
// gopher lives in /usr/gopher.
@@ -117,16 +115,24 @@ func ExampleLookupEnv() {
}
}
- show("USER")
- show("GOPATH")
+ os.Setenv("SOME_KEY", "value")
+ os.Setenv("EMPTY_KEY", "")
+
+ show("SOME_KEY")
+ show("EMPTY_KEY")
+ show("MISSING_KEY")
// Output:
- // USER=gopher
- // GOPATH not set
+ // SOME_KEY=value
+ // EMPTY_KEY=
+ // MISSING_KEY not set
}
func ExampleGetenv() {
- fmt.Printf("%s lives in %s.\n", os.Getenv("USER"), os.Getenv("HOME"))
+ os.Setenv("NAME", "gopher")
+ os.Setenv("BURROW", "/usr/gopher")
+
+ fmt.Printf("%s lives in %s.\n", os.Getenv("NAME"), os.Getenv("BURROW"))
// Output:
// gopher lives in /usr/gopher.
diff --git a/libgo/go/os/exec/exec.go b/libgo/go/os/exec/exec.go
index 88b0a91..1aa3ab9 100644
--- a/libgo/go/os/exec/exec.go
+++ b/libgo/go/os/exec/exec.go
@@ -152,6 +152,15 @@ type Cmd struct {
// followed by the elements of arg, so arg should not include the
// command name itself. For example, Command("echo", "hello").
// Args[0] is always name, not the possibly resolved Path.
+//
+// On Windows, processes receive the whole command line as a single string
+// and do their own parsing. Command combines and quotes Args into a command
+// line string with an algorithm compatible with applications using
+// CommandLineToArgvW (which is the most common way). Notable exceptions are
+// msiexec.exe and cmd.exe (and thus, all batch files), which have a different
+// unquoting algorithm. In these or other similar cases, you can do the
+// quoting yourself and provide the full command line in SysProcAttr.CmdLine,
+// leaving Args empty.
func Command(name string, arg ...string) *Cmd {
cmd := &Cmd{
Path: name,
diff --git a/libgo/go/os/exec/exec_posix_test.go b/libgo/go/os/exec/exec_posix_test.go
index 865b6c3..46799cd 100644
--- a/libgo/go/os/exec/exec_posix_test.go
+++ b/libgo/go/os/exec/exec_posix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package exec_test
diff --git a/libgo/go/os/exec/exec_test.go b/libgo/go/os/exec/exec_test.go
index 1e38285..b7cc9da 100644
--- a/libgo/go/os/exec/exec_test.go
+++ b/libgo/go/os/exec/exec_test.go
@@ -172,6 +172,58 @@ func TestExitStatus(t *testing.T) {
}
}
+func TestExitCode(t *testing.T) {
+ // Test that exit code are returned correctly
+ cmd := helperCommand(t, "exit", "42")
+ cmd.Run()
+ want := 42
+ if runtime.GOOS == "plan9" {
+ want = 1
+ }
+ got := cmd.ProcessState.ExitCode()
+ if want != got {
+ t.Errorf("ExitCode got %d, want %d", got, want)
+ }
+
+ cmd = helperCommand(t, "/no-exist-executable")
+ cmd.Run()
+ want = 2
+ if runtime.GOOS == "plan9" {
+ want = 1
+ }
+ got = cmd.ProcessState.ExitCode()
+ if want != got {
+ t.Errorf("ExitCode got %d, want %d", got, want)
+ }
+
+ cmd = helperCommand(t, "exit", "255")
+ cmd.Run()
+ want = 255
+ if runtime.GOOS == "plan9" {
+ want = 1
+ }
+ got = cmd.ProcessState.ExitCode()
+ if want != got {
+ t.Errorf("ExitCode got %d, want %d", got, want)
+ }
+
+ cmd = helperCommand(t, "cat")
+ cmd.Run()
+ want = 0
+ got = cmd.ProcessState.ExitCode()
+ if want != got {
+ t.Errorf("ExitCode got %d, want %d", got, want)
+ }
+
+ // Test when command does not call Run().
+ cmd = helperCommand(t, "cat")
+ want = -1
+ got = cmd.ProcessState.ExitCode()
+ if want != got {
+ t.Errorf("ExitCode got %d, want %d", got, want)
+ }
+}
+
func TestPipes(t *testing.T) {
check := func(what string, err error) {
if err != nil {
@@ -411,7 +463,7 @@ func basefds() uintptr {
// The poll (epoll/kqueue) descriptor can be numerically
// either between stderr and the testlog-fd, or after
// testlog-fd.
- if poll.PollDescriptor() == n {
+ if poll.IsPollDescriptor(n) {
n++
}
for _, arg := range os.Args {
@@ -424,7 +476,7 @@ func basefds() uintptr {
func closeUnexpectedFds(t *testing.T, m string) {
for fd := basefds(); fd <= 101; fd++ {
- if fd == poll.PollDescriptor() {
+ if poll.IsPollDescriptor(fd) {
continue
}
err := os.NewFile(fd, "").Close()
@@ -686,6 +738,8 @@ func TestHelperProcess(*testing.T) {
ofcmd = "fstat"
case "plan9":
ofcmd = "/bin/cat"
+ case "aix":
+ ofcmd = "procfiles"
}
args := os.Args
@@ -789,7 +843,7 @@ func TestHelperProcess(*testing.T) {
// Now verify that there are no other open fds.
var files []*os.File
for wantfd := basefds() + 1; wantfd <= 100; wantfd++ {
- if wantfd == poll.PollDescriptor() {
+ if poll.IsPollDescriptor(wantfd) {
continue
}
f, err := os.Open(os.Args[0])
@@ -803,6 +857,8 @@ func TestHelperProcess(*testing.T) {
switch runtime.GOOS {
case "plan9":
args = []string{fmt.Sprintf("/proc/%d/fd", os.Getpid())}
+ case "aix":
+ args = []string{fmt.Sprint(os.Getpid())}
default:
args = []string{"-p", fmt.Sprint(os.Getpid())}
}
diff --git a/libgo/go/os/exec/lp_unix_test.go b/libgo/go/os/exec/lp_unix_test.go
index d467acf..e4656ca 100644
--- a/libgo/go/os/exec/lp_unix_test.go
+++ b/libgo/go/os/exec/lp_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package exec
diff --git a/libgo/go/os/exec_plan9.go b/libgo/go/os/exec_plan9.go
index 6b4d28c..bab16cc 100644
--- a/libgo/go/os/exec_plan9.go
+++ b/libgo/go/os/exec_plan9.go
@@ -136,3 +136,13 @@ func (p *ProcessState) String() string {
}
return "exit status: " + p.status.Msg
}
+
+// ExitCode returns the exit code of the exited process, or -1
+// if the process hasn't exited or was terminated by a signal.
+func (p *ProcessState) ExitCode() int {
+ // return -1 if the process hasn't started.
+ if p == nil {
+ return -1
+ }
+ return p.status.ExitStatus()
+}
diff --git a/libgo/go/os/exec_posix.go b/libgo/go/os/exec_posix.go
index dbbb5df..4c82612 100644
--- a/libgo/go/os/exec_posix.go
+++ b/libgo/go/os/exec_posix.go
@@ -10,10 +10,11 @@ import (
"syscall"
)
-// The only signal values guaranteed to be present in the os package
-// on all systems are Interrupt (send the process an interrupt) and
-// Kill (force the process to exit). Interrupt is not implemented on
-// Windows; using it with os.Process.Signal will return an error.
+// The only signal values guaranteed to be present in the os package on all
+// systems are os.Interrupt (send the process an interrupt) and os.Kill (force
+// the process to exit). On Windows, sending os.Interrupt to a process with
+// os.Process.Signal is not implemented; it will return an error instead of
+// sending a signal.
var (
Interrupt Signal = syscall.SIGINT
Kill Signal = syscall.SIGKILL
@@ -106,3 +107,13 @@ func (p *ProcessState) String() string {
}
return res
}
+
+// ExitCode returns the exit code of the exited process, or -1
+// if the process hasn't exited or was terminated by a signal.
+func (p *ProcessState) ExitCode() int {
+ // return -1 if the process hasn't started.
+ if p == nil {
+ return -1
+ }
+ return p.status.ExitStatus()
+}
diff --git a/libgo/go/os/exec_windows.go b/libgo/go/os/exec_windows.go
index d5d553a..38293a0 100644
--- a/libgo/go/os/exec_windows.go
+++ b/libgo/go/os/exec_windows.go
@@ -38,7 +38,8 @@ func (p *Process) wait() (ps *ProcessState, err error) {
// NOTE(brainman): It seems that sometimes process is not dead
// when WaitForSingleObject returns. But we do not know any
// other way to wait for it. Sleeping for a while seems to do
- // the trick sometimes. So we will sleep and smell the roses.
+ // the trick sometimes.
+ // See https://golang.org/issue/25965 for details.
defer time.Sleep(5 * time.Millisecond)
defer p.Release()
return &ProcessState{p.Pid, syscall.WaitStatus{ExitCode: ec}, &u}, nil
diff --git a/libgo/go/os/executable_test.go b/libgo/go/os/executable_test.go
index 4a9a883..d513c87 100644
--- a/libgo/go/os/executable_test.go
+++ b/libgo/go/os/executable_test.go
@@ -36,8 +36,8 @@ func TestExecutable(t *testing.T) {
// forge argv[0] for child, so that we can verify we could correctly
// get real path of the executable without influenced by argv[0].
cmd.Args = []string{"-", "-test.run=XXXX"}
- if runtime.GOOS == "openbsd" {
- // OpenBSD relies on argv[0]
+ if runtime.GOOS == "openbsd" || runtime.GOOS == "aix" {
+ // OpenBSD and AIX rely on argv[0]
cmd.Args[0] = fn
}
cmd.Env = append(os.Environ(), fmt.Sprintf("%s=1", executable_EnvVar))
diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go
index cba70d7..fdead63 100644
--- a/libgo/go/os/file.go
+++ b/libgo/go/os/file.go
@@ -73,7 +73,7 @@ const (
O_CREATE int = syscall.O_CREAT // create a new file if none exists.
O_EXCL int = syscall.O_EXCL // used with O_CREATE, file must not exist.
O_SYNC int = syscall.O_SYNC // open for synchronous I/O.
- O_TRUNC int = syscall.O_TRUNC // if possible, truncate file when opened.
+ O_TRUNC int = syscall.O_TRUNC // truncate regular writable file when opened.
)
// Seek whence values.
@@ -381,6 +381,31 @@ func UserCacheDir() (string, error) {
return dir, nil
}
+// UserHomeDir returns the current user's home directory.
+//
+// On Unix, including macOS, it returns the $HOME environment variable.
+// On Windows, it returns %USERPROFILE%.
+// On Plan 9, it returns the $home environment variable.
+func UserHomeDir() (string, error) {
+ env, enverr := "HOME", "$HOME"
+ switch runtime.GOOS {
+ case "windows":
+ env, enverr = "USERPROFILE", "%userprofile%"
+ case "plan9":
+ env, enverr = "home", "$home"
+ case "nacl", "android":
+ return "/", nil
+ case "darwin":
+ if runtime.GOARCH == "arm" || runtime.GOARCH == "arm64" {
+ return "/", nil
+ }
+ }
+ if v := Getenv(env); v != "" {
+ return v, nil
+ }
+ return "", errors.New(enverr + " is not defined")
+}
+
// Chmod changes the mode of the named file to mode.
// If the file is a symbolic link, it changes the mode of the link's target.
// If there is an error, it will be of type *PathError.
@@ -448,3 +473,12 @@ func (f *File) SetReadDeadline(t time.Time) error {
func (f *File) SetWriteDeadline(t time.Time) error {
return f.setWriteDeadline(t)
}
+
+// SyscallConn returns a raw file.
+// This implements the syscall.Conn interface.
+func (f *File) SyscallConn() (syscall.RawConn, error) {
+ if err := f.checkValid("SyscallConn"); err != nil {
+ return nil, err
+ }
+ return newRawConn(f)
+}
diff --git a/libgo/go/os/file_plan9.go b/libgo/go/os/file_plan9.go
index 2c74403..3fa12e6 100644
--- a/libgo/go/os/file_plan9.go
+++ b/libgo/go/os/file_plan9.go
@@ -534,3 +534,21 @@ func (f *File) checkValid(op string) error {
}
return nil
}
+
+type rawConn struct{}
+
+func (c *rawConn) Control(f func(uintptr)) error {
+ return syscall.EPLAN9
+}
+
+func (c *rawConn) Read(f func(uintptr) bool) error {
+ return syscall.EPLAN9
+}
+
+func (c *rawConn) Write(f func(uintptr) bool) error {
+ return syscall.EPLAN9
+}
+
+func newRawConn(file *File) (*rawConn, error) {
+ return nil, syscall.EPLAN9
+}
diff --git a/libgo/go/os/file_posix.go b/libgo/go/os/file_posix.go
index 9bd1cc7..1c0de5c 100644
--- a/libgo/go/os/file_posix.go
+++ b/libgo/go/os/file_posix.go
@@ -7,6 +7,7 @@
package os
import (
+ "runtime"
"syscall"
"time"
)
@@ -20,7 +21,7 @@ func Readlink(name string) (string, error) {
b := make([]byte, len)
n, e := fixCount(syscall.Readlink(fixLongPath(name), b))
// buffer too small
- if e == syscall.ERANGE {
+ if runtime.GOOS == "aix" && e == syscall.ERANGE {
continue
}
if e != nil {
diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go
index b2aea33..e9ac774 100644
--- a/libgo/go/os/file_unix.go
+++ b/libgo/go/os/file_unix.go
@@ -9,6 +9,7 @@ package os
import (
"internal/poll"
"internal/syscall/unix"
+ "io"
"runtime"
"syscall"
)
@@ -116,23 +117,39 @@ func newFile(fd uintptr, name string, kind newFileKind) *File {
pollable := kind == kindOpenFile || kind == kindPipe || kind == kindNonBlock
- // Don't try to use kqueue with regular files on FreeBSD.
- // It crashes the system unpredictably while running all.bash.
- // Issue 19093.
// If the caller passed a non-blocking filedes (kindNonBlock),
// we assume they know what they are doing so we allow it to be
// used with kqueue.
- if runtime.GOOS == "freebsd" && kind == kindOpenFile {
- pollable = false
- }
-
- // On Darwin, kqueue does not work properly with fifos:
- // closing the last writer does not cause a kqueue event
- // for any readers. See issue #24164.
- if runtime.GOOS == "darwin" && kind == kindOpenFile {
+ if kind == kindOpenFile {
var st syscall.Stat_t
- if err := syscall.Fstat(fdi, &st); err == nil && st.Mode&syscall.S_IFMT == syscall.S_IFIFO {
+ switch runtime.GOOS {
+ case "freebsd":
+ // On FreeBSD before 10.4 it used to crash the
+ // system unpredictably while running all.bash.
+ // When we stop supporting FreeBSD 10 we can merge
+ // this into the dragonfly/netbsd/openbsd case.
+ // Issue 27619.
pollable = false
+
+ case "dragonfly", "netbsd", "openbsd":
+ // Don't try to use kqueue with regular files on *BSDs.
+ // On FreeBSD a regular file is always
+ // reported as ready for writing.
+ // On Dragonfly, NetBSD and OpenBSD the fd is signaled
+ // only once as ready (both read and write).
+ // Issue 19093.
+ if err := syscall.Fstat(fdi, &st); err == nil && st.Mode&syscall.S_IFMT == syscall.S_IFREG {
+ pollable = false
+ }
+
+ case "darwin":
+ // In addition to the behavior described above for regular files,
+ // on Darwin, kqueue does not work properly with fifos:
+ // closing the last writer does not cause a kqueue event
+ // for any readers. See issue #24164.
+ if err := syscall.Fstat(fdi, &st); err == nil && (st.Mode&syscall.S_IFMT == syscall.S_IFIFO || st.Mode&syscall.S_IFMT == syscall.S_IFREG) {
+ pollable = false
+ }
}
}
@@ -230,22 +247,22 @@ func (file *file) close() error {
return syscall.EINVAL
}
var err error
- if e := file.pfd.Close(); e != nil {
- if e == poll.ErrFileClosing {
- e = ErrClosed
- }
- err = &PathError{"close", file.name, e}
- }
-
if file.dirinfo != nil {
syscall.Entersyscall()
i := libc_closedir(file.dirinfo.dir)
errno := syscall.GetErrno()
syscall.Exitsyscall()
file.dirinfo = nil
- if i < 0 && err == nil {
+ if i < 0 && errno != 0 {
err = &PathError{"closedir", file.name, errno}
}
+ } else {
+ if e := file.pfd.Close(); e != nil {
+ if e == poll.ErrFileClosing {
+ e = ErrClosed
+ }
+ err = &PathError{"close", file.name, e}
+ }
}
// no need for a finalizer anymore
@@ -368,3 +385,30 @@ func Symlink(oldname, newname string) error {
}
return nil
}
+
+func (f *File) readdir(n int) (fi []FileInfo, err error) {
+ dirname := f.name
+ if dirname == "" {
+ dirname = "."
+ }
+ names, err := f.Readdirnames(n)
+ fi = make([]FileInfo, 0, len(names))
+ for _, filename := range names {
+ fip, lerr := lstat(dirname + "/" + filename)
+ if IsNotExist(lerr) {
+ // File disappeared between readdir + stat.
+ // Just treat it as if it didn't exist.
+ continue
+ }
+ if lerr != nil {
+ return fi, lerr
+ }
+ fi = append(fi, fip)
+ }
+ if len(fi) == 0 && err == nil && n > 0 {
+ // Per File.Readdir, the slice must be non-empty or err
+ // must be non-nil if n > 0.
+ err = io.EOF
+ }
+ return fi, err
+}
diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go
index 5a77d66..98eba89 100644
--- a/libgo/go/os/os_test.go
+++ b/libgo/go/os/os_test.go
@@ -176,7 +176,6 @@ func TestStatError(t *testing.T) {
defer chtmpdir(t)()
path := "no-such-file"
- Remove(path) // Just in case
fi, err := Stat(path)
if err == nil {
@@ -192,12 +191,10 @@ func TestStatError(t *testing.T) {
testenv.MustHaveSymlink(t)
link := "symlink"
- Remove(link) // Just in case
err = Symlink(path, link)
if err != nil {
t.Fatal(err)
}
- defer Remove(link)
fi, err = Stat(link)
if err == nil {
@@ -267,7 +264,7 @@ func TestRead0(t *testing.T) {
}
}
-// Reading a closed file should should return ErrClosed error
+// Reading a closed file should return ErrClosed error
func TestReadClosed(t *testing.T) {
path := sfdir + "/" + sfname
file, err := Open(path)
@@ -686,12 +683,10 @@ func TestHardLink(t *testing.T) {
defer chtmpdir(t)()
from, to := "hardlinktestfrom", "hardlinktestto"
- Remove(from) // Just in case.
file, err := Create(to)
if err != nil {
t.Fatalf("open %q failed: %v", to, err)
}
- defer Remove(to)
if err = file.Close(); err != nil {
t.Errorf("close %q failed: %v", to, err)
}
@@ -707,7 +702,6 @@ func TestHardLink(t *testing.T) {
t.Errorf("link %q, %q failed to return a valid error", none, none)
}
- defer Remove(from)
tostat, err := Stat(to)
if err != nil {
t.Fatalf("stat %q failed: %v", to, err)
@@ -743,11 +737,8 @@ func TestHardLink(t *testing.T) {
}
// chtmpdir changes the working directory to a new temporary directory and
-// provides a cleanup function. Used when PWD is read-only.
+// provides a cleanup function.
func chtmpdir(t *testing.T) func() {
- if runtime.GOOS != "darwin" || (runtime.GOARCH != "arm" && runtime.GOARCH != "arm64") {
- return func() {} // only needed on darwin/arm{,64}
- }
oldwd, err := Getwd()
if err != nil {
t.Fatalf("chtmpdir: %v", err)
@@ -772,12 +763,10 @@ func TestSymlink(t *testing.T) {
defer chtmpdir(t)()
from, to := "symlinktestfrom", "symlinktestto"
- Remove(from) // Just in case.
file, err := Create(to)
if err != nil {
t.Fatalf("Create(%q) failed: %v", to, err)
}
- defer Remove(to)
if err = file.Close(); err != nil {
t.Errorf("Close(%q) failed: %v", to, err)
}
@@ -785,7 +774,6 @@ func TestSymlink(t *testing.T) {
if err != nil {
t.Fatalf("Symlink(%q, %q) failed: %v", to, from, err)
}
- defer Remove(from)
tostat, err := Lstat(to)
if err != nil {
t.Fatalf("Lstat(%q) failed: %v", to, err)
@@ -839,12 +827,10 @@ func TestLongSymlink(t *testing.T) {
// Long, but not too long: a common limit is 255.
s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s
from := "longsymlinktestfrom"
- Remove(from) // Just in case.
err := Symlink(s, from)
if err != nil {
t.Fatalf("symlink %q, %q failed: %v", s, from, err)
}
- defer Remove(from)
r, err := Readlink(from)
if err != nil {
t.Fatalf("readlink %q failed: %v", from, err)
@@ -857,9 +843,6 @@ func TestLongSymlink(t *testing.T) {
func TestRename(t *testing.T) {
defer chtmpdir(t)()
from, to := "renamefrom", "renameto"
- // Ensure we are not testing the overwrite case here.
- Remove(from)
- Remove(to)
file, err := Create(from)
if err != nil {
@@ -872,7 +855,6 @@ func TestRename(t *testing.T) {
if err != nil {
t.Fatalf("rename %q, %q failed: %v", to, from, err)
}
- defer Remove(to)
_, err = Stat(to)
if err != nil {
t.Errorf("stat %q failed: %v", to, err)
@@ -882,9 +864,6 @@ func TestRename(t *testing.T) {
func TestRenameOverwriteDest(t *testing.T) {
defer chtmpdir(t)()
from, to := "renamefrom", "renameto"
- // Just in case.
- Remove(from)
- Remove(to)
toData := []byte("to")
fromData := []byte("from")
@@ -902,7 +881,6 @@ func TestRenameOverwriteDest(t *testing.T) {
if err != nil {
t.Fatalf("rename %q, %q failed: %v", to, from, err)
}
- defer Remove(to)
_, err = Stat(from)
if err == nil {
@@ -923,9 +901,6 @@ func TestRenameOverwriteDest(t *testing.T) {
func TestRenameFailed(t *testing.T) {
defer chtmpdir(t)()
from, to := "renamefrom", "renameto"
- // Ensure we are not testing the overwrite case here.
- Remove(from)
- Remove(to)
err := Rename(from, to)
switch err := err.(type) {
@@ -941,9 +916,6 @@ func TestRenameFailed(t *testing.T) {
}
case nil:
t.Errorf("rename %q, %q: expected error, got nil", from, to)
-
- // cleanup whatever was placed in "renameto"
- Remove(to)
default:
t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
}
@@ -954,7 +926,6 @@ func TestRenameNotExisting(t *testing.T) {
from, to := "doesnt-exist", "dest"
Mkdir(to, 0777)
- defer Remove(to)
if err := Rename(from, to); !IsNotExist(err) {
t.Errorf("Rename(%q, %q) = %v; want an IsNotExist error", from, to, err)
@@ -965,12 +936,8 @@ func TestRenameToDirFailed(t *testing.T) {
defer chtmpdir(t)()
from, to := "renamefrom", "renameto"
- Remove(from)
- Remove(to)
Mkdir(from, 0777)
Mkdir(to, 0777)
- defer Remove(from)
- defer Remove(to)
err := Rename(from, to)
switch err := err.(type) {
@@ -986,9 +953,6 @@ func TestRenameToDirFailed(t *testing.T) {
}
case nil:
t.Errorf("rename %q, %q: expected error, got nil", from, to)
-
- // cleanup whatever was placed in "renameto"
- Remove(to)
default:
t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
}
@@ -1483,7 +1447,7 @@ func TestOpenNoName(t *testing.T) {
}
}
-func runBinHostname(t *testing.T, argv []string) string {
+func runBinHostname(t *testing.T) string {
// Run /bin/hostname and collect output.
r, w, err := Pipe()
if err != nil {
@@ -1491,6 +1455,10 @@ func runBinHostname(t *testing.T, argv []string) string {
}
defer r.Close()
const path = "/bin/hostname"
+ argv := []string{"hostname"}
+ if runtime.GOOS == "aix" {
+ argv = []string{"hostname", "-s"}
+ }
p, err := StartProcess(path, argv, &ProcAttr{Files: []*File{nil, w, Stderr}})
if err != nil {
if _, err := Stat(path); IsNotExist(err) {
@@ -1561,12 +1529,7 @@ func TestHostname(t *testing.T) {
// Check internal Hostname() against the output of /bin/hostname.
// Allow that the internal Hostname returns a Fully Qualified Domain Name
// and the /bin/hostname only returns the first component
- var want string
- if runtime.GOOS == "aix" {
- want = runBinHostname(t, []string{"hostname", "-s"})
- } else {
- want = runBinHostname(t, []string{"hostname"})
- }
+ want := runBinHostname(t)
if hostname != want {
i := strings.Index(hostname, ".")
if i < 0 || hostname[0:i] != want {
@@ -1701,7 +1664,6 @@ func writeFile(t *testing.T, fname string, flag int, text string) string {
func TestAppend(t *testing.T) {
defer chtmpdir(t)()
const f = "append.txt"
- defer Remove(f)
s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
if s != "new" {
t.Fatalf("writeFile: have %q want %q", s, "new")
@@ -1768,13 +1730,11 @@ func TestSameFile(t *testing.T) {
if err != nil {
t.Fatalf("Create(a): %v", err)
}
- defer Remove(fa.Name())
fa.Close()
fb, err := Create("b")
if err != nil {
t.Fatalf("Create(b): %v", err)
}
- defer Remove(fb.Name())
fb.Close()
ia1, err := Stat("a")
@@ -2336,3 +2296,20 @@ func TestDoubleCloseError(t *testing.T) {
t.Logf("second close returned expected error %q", err)
}
}
+
+func TestUserHomeDir(t *testing.T) {
+ dir, err := UserHomeDir()
+ if dir == "" && err == nil {
+ t.Fatal("UserHomeDir returned an empty string but no error")
+ }
+ if err != nil {
+ t.Skipf("UserHomeDir failed: %v", err)
+ }
+ fi, err := Stat(dir)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !fi.IsDir() {
+ t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode())
+ }
+}
diff --git a/libgo/go/os/os_unix_test.go b/libgo/go/os/os_unix_test.go
index 54f121e..2aa930e 100644
--- a/libgo/go/os/os_unix_test.go
+++ b/libgo/go/os/os_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package os_test
@@ -22,6 +22,9 @@ func init() {
isReadonlyError = func(err error) bool { return err == syscall.EROFS }
}
+// For TestRawConnReadWrite.
+type syscallDescriptor = int
+
func checkUidGid(t *testing.T, path string, uid, gid int) {
dir, err := Lstat(path)
if err != nil {
@@ -234,7 +237,7 @@ func newFileTest(t *testing.T, blocking bool) {
}
defer syscall.Close(p[1])
- // Set the the read-side to non-blocking.
+ // Set the read-side to non-blocking.
if !blocking {
if err := syscall.SetNonblock(p[0], true); err != nil {
syscall.Close(p[0])
diff --git a/libgo/go/os/path.go b/libgo/go/os/path.go
index cdfbc18..30cc6c8 100644
--- a/libgo/go/os/path.go
+++ b/libgo/go/os/path.go
@@ -5,7 +5,6 @@
package os
import (
- "io"
"syscall"
)
@@ -59,100 +58,13 @@ func MkdirAll(path string, perm FileMode) error {
return nil
}
-// RemoveAll removes path and any children it contains.
-// It removes everything it can but returns the first error
-// it encounters. If the path does not exist, RemoveAll
-// returns nil (no error).
-func RemoveAll(path string) error {
- // Simple case: if Remove works, we're done.
- err := Remove(path)
- if err == nil || IsNotExist(err) {
- return nil
+// endsWithDot reports whether the final component of path is ".".
+func endsWithDot(path string) bool {
+ if path == "." {
+ return true
}
-
- // Otherwise, is this a directory we need to recurse into?
- dir, serr := Lstat(path)
- if serr != nil {
- if serr, ok := serr.(*PathError); ok && (IsNotExist(serr.Err) || serr.Err == syscall.ENOTDIR) {
- return nil
- }
- return serr
- }
- if !dir.IsDir() {
- // Not a directory; return the error from Remove.
- return err
- }
-
- // Remove contents & return first error.
- err = nil
- for {
- fd, err := Open(path)
- if err != nil {
- if IsNotExist(err) {
- // Already deleted by someone else.
- return nil
- }
- return err
- }
-
- const request = 1024
- names, err1 := fd.Readdirnames(request)
-
- // Removing files from the directory may have caused
- // the OS to reshuffle it. Simply calling Readdirnames
- // again may skip some entries. The only reliable way
- // to avoid this is to close and re-open the
- // directory. See issue 20841.
- fd.Close()
-
- for _, name := range names {
- err1 := RemoveAll(path + string(PathSeparator) + name)
- if err == nil {
- err = err1
- }
- }
-
- if err1 == io.EOF {
- break
- }
- // If Readdirnames returned an error, use it.
- if err == nil {
- err = err1
- }
- if len(names) == 0 {
- break
- }
-
- // We don't want to re-open unnecessarily, so if we
- // got fewer than request names from Readdirnames, try
- // simply removing the directory now. If that
- // succeeds, we are done.
- if len(names) < request {
- err1 := Remove(path)
- if err1 == nil || IsNotExist(err1) {
- return nil
- }
-
- if err != nil {
- // We got some error removing the
- // directory contents, and since we
- // read fewer names than we requested
- // there probably aren't more files to
- // remove. Don't loop around to read
- // the directory again. We'll probably
- // just get the same error.
- return err
- }
- }
- }
-
- // Remove directory.
- err1 := Remove(path)
- if err1 == nil || IsNotExist(err1) {
- return nil
- }
- if err == nil {
- err = err1
+ if len(path) >= 2 && path[len(path)-1] == '.' && IsPathSeparator(path[len(path)-2]) {
+ return true
}
- return err
+ return false
}
diff --git a/libgo/go/os/path_test.go b/libgo/go/os/path_test.go
index f58c7e7..6cb25bc 100644
--- a/libgo/go/os/path_test.go
+++ b/libgo/go/os/path_test.go
@@ -5,7 +5,6 @@
package os_test
import (
- "fmt"
"internal/testenv"
"io/ioutil"
. "os"
@@ -76,130 +75,6 @@ func TestMkdirAll(t *testing.T) {
}
}
-func TestRemoveAll(t *testing.T) {
- tmpDir := TempDir()
- // Work directory.
- path := tmpDir + "/_TestRemoveAll_"
- fpath := path + "/file"
- dpath := path + "/dir"
-
- // Make directory with 1 file and remove.
- if err := MkdirAll(path, 0777); err != nil {
- t.Fatalf("MkdirAll %q: %s", path, err)
- }
- fd, err := Create(fpath)
- if err != nil {
- t.Fatalf("create %q: %s", fpath, err)
- }
- fd.Close()
- if err = RemoveAll(path); err != nil {
- t.Fatalf("RemoveAll %q (first): %s", path, err)
- }
- if _, err = Lstat(path); err == nil {
- t.Fatalf("Lstat %q succeeded after RemoveAll (first)", path)
- }
-
- // Make directory with file and subdirectory and remove.
- if err = MkdirAll(dpath, 0777); err != nil {
- t.Fatalf("MkdirAll %q: %s", dpath, err)
- }
- fd, err = Create(fpath)
- if err != nil {
- t.Fatalf("create %q: %s", fpath, err)
- }
- fd.Close()
- fd, err = Create(dpath + "/file")
- if err != nil {
- t.Fatalf("create %q: %s", fpath, err)
- }
- fd.Close()
- if err = RemoveAll(path); err != nil {
- t.Fatalf("RemoveAll %q (second): %s", path, err)
- }
- if _, err := Lstat(path); err == nil {
- t.Fatalf("Lstat %q succeeded after RemoveAll (second)", path)
- }
-
- // Determine if we should run the following test.
- testit := true
- if runtime.GOOS == "windows" {
- // Chmod is not supported under windows.
- testit = false
- } else {
- // Test fails as root.
- testit = Getuid() != 0
- }
- if testit {
- // Make directory with file and subdirectory and trigger error.
- if err = MkdirAll(dpath, 0777); err != nil {
- t.Fatalf("MkdirAll %q: %s", dpath, err)
- }
-
- for _, s := range []string{fpath, dpath + "/file1", path + "/zzz"} {
- fd, err = Create(s)
- if err != nil {
- t.Fatalf("create %q: %s", s, err)
- }
- fd.Close()
- }
- if err = Chmod(dpath, 0); err != nil {
- t.Fatalf("Chmod %q 0: %s", dpath, err)
- }
-
- // No error checking here: either RemoveAll
- // will or won't be able to remove dpath;
- // either way we want to see if it removes fpath
- // and path/zzz. Reasons why RemoveAll might
- // succeed in removing dpath as well include:
- // * running as root
- // * running on a file system without permissions (FAT)
- RemoveAll(path)
- Chmod(dpath, 0777)
-
- for _, s := range []string{fpath, path + "/zzz"} {
- if _, err = Lstat(s); err == nil {
- t.Fatalf("Lstat %q succeeded after partial RemoveAll", s)
- }
- }
- }
- if err = RemoveAll(path); err != nil {
- t.Fatalf("RemoveAll %q after partial RemoveAll: %s", path, err)
- }
- if _, err = Lstat(path); err == nil {
- t.Fatalf("Lstat %q succeeded after RemoveAll (final)", path)
- }
-}
-
-// Test RemoveAll on a large directory.
-func TestRemoveAllLarge(t *testing.T) {
- if testing.Short() {
- t.Skip("skipping in short mode")
- }
-
- tmpDir := TempDir()
- // Work directory.
- path := tmpDir + "/_TestRemoveAllLarge_"
-
- // Make directory with 1000 files and remove.
- if err := MkdirAll(path, 0777); err != nil {
- t.Fatalf("MkdirAll %q: %s", path, err)
- }
- for i := 0; i < 1000; i++ {
- fpath := fmt.Sprintf("%s/file%d", path, i)
- fd, err := Create(fpath)
- if err != nil {
- t.Fatalf("create %q: %s", fpath, err)
- }
- fd.Close()
- }
- if err := RemoveAll(path); err != nil {
- t.Fatalf("RemoveAll %q: %s", path, err)
- }
- if _, err := Lstat(path); err == nil {
- t.Fatalf("Lstat %q succeeded after RemoveAll", path)
- }
-}
-
func TestMkdirAllWithSymlink(t *testing.T) {
testenv.MustHaveSymlink(t)
diff --git a/libgo/go/os/path_unix.go b/libgo/go/os/path_unix.go
index 3cb0e3a..be373a5 100644
--- a/libgo/go/os/path_unix.go
+++ b/libgo/go/os/path_unix.go
@@ -16,7 +16,7 @@ func IsPathSeparator(c uint8) bool {
return PathSeparator == c
}
-// basename removes trailing slashes and the leading directory name from path name
+// basename removes trailing slashes and the leading directory name from path name.
func basename(name string) string {
i := len(name) - 1
// Remove trailing slashes
@@ -34,6 +34,32 @@ func basename(name string) string {
return name
}
+// splitPath returns the base name and parent directory.
+func splitPath(path string) (string, string) {
+ // if no better parent is found, the path is relative from "here"
+ dirname := "."
+ // if no slashes in path, base is path
+ basename := path
+
+ i := len(path) - 1
+
+ // Remove trailing slashes
+ for ; i > 0 && path[i] == '/'; i-- {
+ path = path[:i]
+ }
+
+ // Remove leading directory path
+ for i--; i >= 0; i-- {
+ if path[i] == '/' {
+ dirname = path[:i+1]
+ basename = path[i+1:]
+ break
+ }
+ }
+
+ return dirname, basename
+}
+
func fixRootDirectory(p string) string {
return p
}
diff --git a/libgo/go/os/path_windows_test.go b/libgo/go/os/path_windows_test.go
index 00a3e63..f1745ad 100644
--- a/libgo/go/os/path_windows_test.go
+++ b/libgo/go/os/path_windows_test.go
@@ -38,10 +38,10 @@ func TestFixLongPath(t *testing.T) {
{`\\?\c:\long\foo.txt`, `\\?\c:\long\foo.txt`},
{`\\?\c:\long/foo.txt`, `\\?\c:\long/foo.txt`},
} {
- in := strings.Replace(test.in, "long", veryLong, -1)
- want := strings.Replace(test.want, "long", veryLong, -1)
+ in := strings.ReplaceAll(test.in, "long", veryLong)
+ want := strings.ReplaceAll(test.want, "long", veryLong)
if got := os.FixLongPath(in); got != want {
- got = strings.Replace(got, veryLong, "long", -1)
+ got = strings.ReplaceAll(got, veryLong, "long")
t.Errorf("fixLongPath(%q) = %q; want %q", test.in, got, test.want)
}
}
diff --git a/libgo/go/os/pipe_test.go b/libgo/go/os/pipe_test.go
index 59d31e5..779b2bd 100644
--- a/libgo/go/os/pipe_test.go
+++ b/libgo/go/os/pipe_test.go
@@ -131,7 +131,7 @@ func testClosedPipeRace(t *testing.T, read bool) {
if !read {
// Get the amount we have to write to overload a pipe
// with no reader.
- limit = 65537
+ limit = 131073
if b, err := ioutil.ReadFile("/proc/sys/fs/pipe-max-size"); err == nil {
if i, err := strconv.Atoi(strings.TrimSpace(string(b))); err == nil {
limit = i + 1
diff --git a/libgo/go/os/rawconn.go b/libgo/go/os/rawconn.go
new file mode 100644
index 0000000..9e11cda
--- /dev/null
+++ b/libgo/go/os/rawconn.go
@@ -0,0 +1,47 @@
+// Copyright 2018 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.
+
+// +build !plan9
+
+package os
+
+import (
+ "runtime"
+)
+
+// rawConn implements syscall.RawConn.
+type rawConn struct {
+ file *File
+}
+
+func (c *rawConn) Control(f func(uintptr)) error {
+ if err := c.file.checkValid("SyscallConn.Control"); err != nil {
+ return err
+ }
+ err := c.file.pfd.RawControl(f)
+ runtime.KeepAlive(c.file)
+ return err
+}
+
+func (c *rawConn) Read(f func(uintptr) bool) error {
+ if err := c.file.checkValid("SyscallConn.Read"); err != nil {
+ return err
+ }
+ err := c.file.pfd.RawRead(f)
+ runtime.KeepAlive(c.file)
+ return err
+}
+
+func (c *rawConn) Write(f func(uintptr) bool) error {
+ if err := c.file.checkValid("SyscallConn.Write"); err != nil {
+ return err
+ }
+ err := c.file.pfd.RawWrite(f)
+ runtime.KeepAlive(c.file)
+ return err
+}
+
+func newRawConn(file *File) (*rawConn, error) {
+ return &rawConn{file: file}, nil
+}
diff --git a/libgo/go/os/rawconn_test.go b/libgo/go/os/rawconn_test.go
new file mode 100644
index 0000000..820150d
--- /dev/null
+++ b/libgo/go/os/rawconn_test.go
@@ -0,0 +1,65 @@
+// Copyright 2018 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.
+
+// Test use of raw connections.
+// +build !plan9,!nacl,!js
+
+package os_test
+
+import (
+ "os"
+ "syscall"
+ "testing"
+)
+
+func TestRawConnReadWrite(t *testing.T) {
+ t.Parallel()
+
+ r, w, err := os.Pipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer r.Close()
+ defer w.Close()
+
+ rconn, err := r.SyscallConn()
+ if err != nil {
+ t.Fatal(err)
+ }
+ wconn, err := w.SyscallConn()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var operr error
+ err = wconn.Write(func(s uintptr) bool {
+ _, operr = syscall.Write(syscallDescriptor(s), []byte{'b'})
+ return operr != syscall.EAGAIN
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if operr != nil {
+ t.Fatal(err)
+ }
+
+ var n int
+ buf := make([]byte, 1)
+ err = rconn.Read(func(s uintptr) bool {
+ n, operr = syscall.Read(syscallDescriptor(s), buf)
+ return operr != syscall.EAGAIN
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ if operr != nil {
+ t.Fatal(operr)
+ }
+ if n != 1 {
+ t.Errorf("read %d bytes, expected 1", n)
+ }
+ if buf[0] != 'b' {
+ t.Errorf("read %q, expected %q", buf, "b")
+ }
+}
diff --git a/libgo/go/os/removeall_at.go b/libgo/go/os/removeall_at.go
new file mode 100644
index 0000000..f0fed6d
--- /dev/null
+++ b/libgo/go/os/removeall_at.go
@@ -0,0 +1,138 @@
+// Copyright 2018 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.
+
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package os
+
+import (
+ "internal/syscall/unix"
+ "io"
+ "syscall"
+)
+
+func RemoveAll(path string) error {
+ if path == "" {
+ // fail silently to retain compatibility with previous behavior
+ // of RemoveAll. See issue 28830.
+ return nil
+ }
+
+ // The rmdir system call does not permit removing ".",
+ // so we don't permit it either.
+ if endsWithDot(path) {
+ return &PathError{"RemoveAll", path, syscall.EINVAL}
+ }
+
+ // Simple case: if Remove works, we're done.
+ err := Remove(path)
+ if err == nil || IsNotExist(err) {
+ return nil
+ }
+
+ // RemoveAll recurses by deleting the path base from
+ // its parent directory
+ parentDir, base := splitPath(path)
+
+ parent, err := Open(parentDir)
+ if IsNotExist(err) {
+ // If parent does not exist, base cannot exist. Fail silently
+ return nil
+ }
+ if err != nil {
+ return err
+ }
+ defer parent.Close()
+
+ return removeAllFrom(parent, base)
+}
+
+func removeAllFrom(parent *File, path string) error {
+ parentFd := int(parent.Fd())
+ // Simple case: if Unlink (aka remove) works, we're done.
+ err := unix.Unlinkat(parentFd, path, 0)
+ if err == nil || IsNotExist(err) {
+ return nil
+ }
+
+ // If not a "is directory" error, we have a problem
+ if err != syscall.EISDIR && err != syscall.EPERM {
+ return err
+ }
+
+ // Is this a directory we need to recurse into?
+ var statInfo syscall.Stat_t
+ statErr := unix.Fstatat(parentFd, path, &statInfo, unix.AT_SYMLINK_NOFOLLOW)
+ if statErr != nil {
+ return statErr
+ }
+ if statInfo.Mode&syscall.S_IFMT != syscall.S_IFDIR {
+ // Not a directory; return the error from the Remove
+ return err
+ }
+
+ // Remove the directory's entries
+ var recurseErr error
+ for {
+ const request = 1024
+
+ // Open the directory to recurse into
+ file, err := openFdAt(parentFd, path)
+ if err != nil {
+ if IsNotExist(err) {
+ return nil
+ }
+ return err
+ }
+
+ names, readErr := file.Readdirnames(request)
+ // Errors other than EOF should stop us from continuing
+ if readErr != nil && readErr != io.EOF {
+ file.Close()
+ if IsNotExist(readErr) {
+ return nil
+ }
+ return readErr
+ }
+
+ for _, name := range names {
+ err := removeAllFrom(file, name)
+ if err != nil {
+ recurseErr = err
+ }
+ }
+
+ // Removing files from the directory may have caused
+ // the OS to reshuffle it. Simply calling Readdirnames
+ // again may skip some entries. The only reliable way
+ // to avoid this is to close and re-open the
+ // directory. See issue 20841.
+ file.Close()
+
+ // Finish when the end of the directory is reached
+ if len(names) < request {
+ break
+ }
+ }
+
+ // Remove the directory itself
+ unlinkError := unix.Unlinkat(parentFd, path, unix.AT_REMOVEDIR)
+ if unlinkError == nil || IsNotExist(unlinkError) {
+ return nil
+ }
+
+ if recurseErr != nil {
+ return recurseErr
+ }
+ return unlinkError
+}
+
+func openFdAt(fd int, path string) (*File, error) {
+ fd, err := unix.Openat(fd, path, O_RDONLY, 0)
+ if err != nil {
+ return nil, err
+ }
+
+ return NewFile(uintptr(fd), path), nil
+}
diff --git a/libgo/go/os/removeall_noat.go b/libgo/go/os/removeall_noat.go
new file mode 100644
index 0000000..80527e2
--- /dev/null
+++ b/libgo/go/os/removeall_noat.go
@@ -0,0 +1,123 @@
+// Copyright 2018 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.
+
+// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
+
+package os
+
+import (
+ "io"
+ "syscall"
+)
+
+// RemoveAll removes path and any children it contains.
+// It removes everything it can but returns the first error
+// it encounters. If the path does not exist, RemoveAll
+// returns nil (no error).
+func RemoveAll(path string) error {
+ if path == "" {
+ // fail silently to retain compatibility with previous behavior
+ // of RemoveAll. See issue 28830.
+ return nil
+ }
+
+ // The rmdir system call permits removing "." on Plan 9,
+ // so we don't permit it to remain consistent with the
+ // "at" implementation of RemoveAll.
+ if endsWithDot(path) {
+ return &PathError{"RemoveAll", path, syscall.EINVAL}
+ }
+
+ // Simple case: if Remove works, we're done.
+ err := Remove(path)
+ if err == nil || IsNotExist(err) {
+ return nil
+ }
+
+ // Otherwise, is this a directory we need to recurse into?
+ dir, serr := Lstat(path)
+ if serr != nil {
+ if serr, ok := serr.(*PathError); ok && (IsNotExist(serr.Err) || serr.Err == syscall.ENOTDIR) {
+ return nil
+ }
+ return serr
+ }
+ if !dir.IsDir() {
+ // Not a directory; return the error from Remove.
+ return err
+ }
+
+ // Remove contents & return first error.
+ err = nil
+ for {
+ fd, err := Open(path)
+ if err != nil {
+ if IsNotExist(err) {
+ // Already deleted by someone else.
+ return nil
+ }
+ return err
+ }
+
+ const request = 1024
+ names, err1 := fd.Readdirnames(request)
+
+ // Removing files from the directory may have caused
+ // the OS to reshuffle it. Simply calling Readdirnames
+ // again may skip some entries. The only reliable way
+ // to avoid this is to close and re-open the
+ // directory. See issue 20841.
+ fd.Close()
+
+ for _, name := range names {
+ err1 := RemoveAll(path + string(PathSeparator) + name)
+ if err == nil {
+ err = err1
+ }
+ }
+
+ if err1 == io.EOF {
+ break
+ }
+ // If Readdirnames returned an error, use it.
+ if err == nil {
+ err = err1
+ }
+ if len(names) == 0 {
+ break
+ }
+
+ // We don't want to re-open unnecessarily, so if we
+ // got fewer than request names from Readdirnames, try
+ // simply removing the directory now. If that
+ // succeeds, we are done.
+ if len(names) < request {
+ err1 := Remove(path)
+ if err1 == nil || IsNotExist(err1) {
+ return nil
+ }
+
+ if err != nil {
+ // We got some error removing the
+ // directory contents, and since we
+ // read fewer names than we requested
+ // there probably aren't more files to
+ // remove. Don't loop around to read
+ // the directory again. We'll probably
+ // just get the same error.
+ return err
+ }
+ }
+ }
+
+ // Remove directory.
+ err1 := Remove(path)
+ if err1 == nil || IsNotExist(err1) {
+ return nil
+ }
+ if err == nil {
+ err = err1
+ }
+ return err
+}
diff --git a/libgo/go/os/removeall_test.go b/libgo/go/os/removeall_test.go
new file mode 100644
index 0000000..0f7dce0
--- /dev/null
+++ b/libgo/go/os/removeall_test.go
@@ -0,0 +1,294 @@
+// Copyright 2018 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.
+
+package os_test
+
+import (
+ "fmt"
+ "io/ioutil"
+ . "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+)
+
+func TestRemoveAll(t *testing.T) {
+ tmpDir, err := ioutil.TempDir("", "TestRemoveAll-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer RemoveAll(tmpDir)
+
+ if err := RemoveAll(""); err != nil {
+ t.Errorf("RemoveAll(\"\"): %v; want nil", err)
+ }
+
+ file := filepath.Join(tmpDir, "file")
+ path := filepath.Join(tmpDir, "_TestRemoveAll_")
+ fpath := filepath.Join(path, "file")
+ dpath := filepath.Join(path, "dir")
+
+ // Make a regular file and remove
+ fd, err := Create(file)
+ if err != nil {
+ t.Fatalf("create %q: %s", file, err)
+ }
+ fd.Close()
+ if err = RemoveAll(file); err != nil {
+ t.Fatalf("RemoveAll %q (first): %s", file, err)
+ }
+ if _, err = Lstat(file); err == nil {
+ t.Fatalf("Lstat %q succeeded after RemoveAll (first)", file)
+ }
+
+ // Make directory with 1 file and remove.
+ if err := MkdirAll(path, 0777); err != nil {
+ t.Fatalf("MkdirAll %q: %s", path, err)
+ }
+ fd, err = Create(fpath)
+ if err != nil {
+ t.Fatalf("create %q: %s", fpath, err)
+ }
+ fd.Close()
+ if err = RemoveAll(path); err != nil {
+ t.Fatalf("RemoveAll %q (second): %s", path, err)
+ }
+ if _, err = Lstat(path); err == nil {
+ t.Fatalf("Lstat %q succeeded after RemoveAll (second)", path)
+ }
+
+ // Make directory with file and subdirectory and remove.
+ if err = MkdirAll(dpath, 0777); err != nil {
+ t.Fatalf("MkdirAll %q: %s", dpath, err)
+ }
+ fd, err = Create(fpath)
+ if err != nil {
+ t.Fatalf("create %q: %s", fpath, err)
+ }
+ fd.Close()
+ fd, err = Create(dpath + "/file")
+ if err != nil {
+ t.Fatalf("create %q: %s", fpath, err)
+ }
+ fd.Close()
+ if err = RemoveAll(path); err != nil {
+ t.Fatalf("RemoveAll %q (third): %s", path, err)
+ }
+ if _, err := Lstat(path); err == nil {
+ t.Fatalf("Lstat %q succeeded after RemoveAll (third)", path)
+ }
+
+ // Determine if we should run the following test.
+ testit := true
+ if runtime.GOOS == "windows" {
+ // Chmod is not supported under windows.
+ testit = false
+ } else {
+ // Test fails as root.
+ testit = Getuid() != 0
+ }
+ if testit {
+ // Make directory with file and subdirectory and trigger error.
+ if err = MkdirAll(dpath, 0777); err != nil {
+ t.Fatalf("MkdirAll %q: %s", dpath, err)
+ }
+
+ for _, s := range []string{fpath, dpath + "/file1", path + "/zzz"} {
+ fd, err = Create(s)
+ if err != nil {
+ t.Fatalf("create %q: %s", s, err)
+ }
+ fd.Close()
+ }
+ if err = Chmod(dpath, 0); err != nil {
+ t.Fatalf("Chmod %q 0: %s", dpath, err)
+ }
+
+ // No error checking here: either RemoveAll
+ // will or won't be able to remove dpath;
+ // either way we want to see if it removes fpath
+ // and path/zzz. Reasons why RemoveAll might
+ // succeed in removing dpath as well include:
+ // * running as root
+ // * running on a file system without permissions (FAT)
+ RemoveAll(path)
+ Chmod(dpath, 0777)
+
+ for _, s := range []string{fpath, path + "/zzz"} {
+ if _, err = Lstat(s); err == nil {
+ t.Fatalf("Lstat %q succeeded after partial RemoveAll", s)
+ }
+ }
+ }
+ if err = RemoveAll(path); err != nil {
+ t.Fatalf("RemoveAll %q after partial RemoveAll: %s", path, err)
+ }
+ if _, err = Lstat(path); err == nil {
+ t.Fatalf("Lstat %q succeeded after RemoveAll (final)", path)
+ }
+}
+
+// Test RemoveAll on a large directory.
+func TestRemoveAllLarge(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+
+ tmpDir, err := ioutil.TempDir("", "TestRemoveAll-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer RemoveAll(tmpDir)
+
+ path := filepath.Join(tmpDir, "_TestRemoveAllLarge_")
+
+ // Make directory with 1000 files and remove.
+ if err := MkdirAll(path, 0777); err != nil {
+ t.Fatalf("MkdirAll %q: %s", path, err)
+ }
+ for i := 0; i < 1000; i++ {
+ fpath := fmt.Sprintf("%s/file%d", path, i)
+ fd, err := Create(fpath)
+ if err != nil {
+ t.Fatalf("create %q: %s", fpath, err)
+ }
+ fd.Close()
+ }
+ if err := RemoveAll(path); err != nil {
+ t.Fatalf("RemoveAll %q: %s", path, err)
+ }
+ if _, err := Lstat(path); err == nil {
+ t.Fatalf("Lstat %q succeeded after RemoveAll", path)
+ }
+}
+
+func TestRemoveAllLongPath(t *testing.T) {
+ switch runtime.GOOS {
+ case "aix", "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
+ break
+ default:
+ t.Skip("skipping for not implemented platforms")
+ }
+
+ prevDir, err := Getwd()
+ if err != nil {
+ t.Fatalf("Could not get wd: %s", err)
+ }
+
+ startPath, err := ioutil.TempDir("", "TestRemoveAllLongPath-")
+ if err != nil {
+ t.Fatalf("Could not create TempDir: %s", err)
+ }
+ defer RemoveAll(startPath)
+
+ err = Chdir(startPath)
+ if err != nil {
+ t.Fatalf("Could not chdir %s: %s", startPath, err)
+ }
+
+ // Removing paths with over 4096 chars commonly fails
+ for i := 0; i < 41; i++ {
+ name := strings.Repeat("a", 100)
+
+ err = Mkdir(name, 0755)
+ if err != nil {
+ t.Fatalf("Could not mkdir %s: %s", name, err)
+ }
+
+ err = Chdir(name)
+ if err != nil {
+ t.Fatalf("Could not chdir %s: %s", name, err)
+ }
+ }
+
+ err = Chdir(prevDir)
+ if err != nil {
+ t.Fatalf("Could not chdir %s: %s", prevDir, err)
+ }
+
+ err = RemoveAll(startPath)
+ if err != nil {
+ t.Errorf("RemoveAll could not remove long file path %s: %s", startPath, err)
+ }
+}
+
+func TestRemoveAllDot(t *testing.T) {
+ prevDir, err := Getwd()
+ if err != nil {
+ t.Fatalf("Could not get wd: %s", err)
+ }
+ tempDir, err := ioutil.TempDir("", "TestRemoveAllDot-")
+ if err != nil {
+ t.Fatalf("Could not create TempDir: %s", err)
+ }
+ defer RemoveAll(tempDir)
+
+ err = Chdir(tempDir)
+ if err != nil {
+ t.Fatalf("Could not chdir to tempdir: %s", err)
+ }
+
+ err = RemoveAll(".")
+ if err == nil {
+ t.Errorf("RemoveAll succeed to remove .")
+ }
+
+ err = Chdir(prevDir)
+ if err != nil {
+ t.Fatalf("Could not chdir %s: %s", prevDir, err)
+ }
+}
+
+func TestRemoveAllDotDot(t *testing.T) {
+ t.Parallel()
+
+ tempDir, err := ioutil.TempDir("", "TestRemoveAllDotDot-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer RemoveAll(tempDir)
+
+ subdir := filepath.Join(tempDir, "x")
+ subsubdir := filepath.Join(subdir, "y")
+ if err := MkdirAll(subsubdir, 0777); err != nil {
+ t.Fatal(err)
+ }
+ if err := RemoveAll(filepath.Join(subsubdir, "..")); err != nil {
+ t.Error(err)
+ }
+ for _, dir := range []string{subsubdir, subdir} {
+ if _, err := Stat(dir); err == nil {
+ t.Errorf("%s: exists after RemoveAll", dir)
+ }
+ }
+}
+
+// Issue #29178.
+func TestRemoveReadOnlyDir(t *testing.T) {
+ t.Parallel()
+
+ tempDir, err := ioutil.TempDir("", "TestRemoveReadOnlyDir-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer RemoveAll(tempDir)
+
+ subdir := filepath.Join(tempDir, "x")
+ if err := Mkdir(subdir, 0); err != nil {
+ t.Fatal(err)
+ }
+
+ // If an error occurs make it more likely that removing the
+ // temporary directory will succeed.
+ defer Chmod(subdir, 0777)
+
+ if err := RemoveAll(subdir); err != nil {
+ t.Fatal(err)
+ }
+
+ if _, err := Stat(subdir); err == nil {
+ t.Error("subdirectory was not removed")
+ }
+}
diff --git a/libgo/go/os/signal/internal/pty/pty.go b/libgo/go/os/signal/internal/pty/pty.go
index e52d19a..a82cf05 100644
--- a/libgo/go/os/signal/internal/pty/pty.go
+++ b/libgo/go/os/signal/internal/pty/pty.go
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
// +build aix darwin dragonfly freebsd linux,!android netbsd openbsd solaris
+// +build cgo
// Package pty is a simple pseudo-terminal package for Unix systems,
// implemented by calling C functions via cgo.
diff --git a/libgo/go/os/signal/signal_cgo_test.go b/libgo/go/os/signal/signal_cgo_test.go
index 16aeea8..3c23090 100644
--- a/libgo/go/os/signal/signal_cgo_test.go
+++ b/libgo/go/os/signal/signal_cgo_test.go
@@ -22,6 +22,7 @@ import (
"os/signal/internal/pty"
"strconv"
"strings"
+ "sync"
"syscall"
"testing"
"time"
@@ -113,7 +114,11 @@ func TestTerminalSignal(t *testing.T) {
const prompt = "prompt> "
// Read data from master in the background.
+ var wg sync.WaitGroup
+ wg.Add(1)
+ defer wg.Wait()
go func() {
+ defer wg.Done()
input := bufio.NewReader(master)
var line, handled []byte
for {
diff --git a/libgo/go/os/stat_aix.go b/libgo/go/os/stat_aix.go
index 265761f..5301827 100644
--- a/libgo/go/os/stat_aix.go
+++ b/libgo/go/os/stat_aix.go
@@ -1,4 +1,4 @@
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2018 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.
diff --git a/libgo/go/os/stat_test.go b/libgo/go/os/stat_test.go
new file mode 100644
index 0000000..60f3b4c
--- /dev/null
+++ b/libgo/go/os/stat_test.go
@@ -0,0 +1,292 @@
+// Copyright 2018 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.
+
+package os_test
+
+import (
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "runtime"
+ "testing"
+)
+
+// testStatAndLstat verifies that all os.Stat, os.Lstat os.File.Stat and os.Readdir work.
+func testStatAndLstat(t *testing.T, path string, isLink bool, statCheck, lstatCheck func(*testing.T, string, os.FileInfo)) {
+ // test os.Stat
+ sfi, err := os.Stat(path)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ statCheck(t, path, sfi)
+
+ // test os.Lstat
+ lsfi, err := os.Lstat(path)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ lstatCheck(t, path, lsfi)
+
+ if isLink {
+ if os.SameFile(sfi, lsfi) {
+ t.Errorf("stat and lstat of %q should not be the same", path)
+ }
+ } else {
+ if !os.SameFile(sfi, lsfi) {
+ t.Errorf("stat and lstat of %q should be the same", path)
+ }
+ }
+
+ // test os.File.Stat
+ f, err := os.Open(path)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer f.Close()
+
+ sfi2, err := f.Stat()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ statCheck(t, path, sfi2)
+
+ if !os.SameFile(sfi, sfi2) {
+ t.Errorf("stat of open %q file and stat of %q should be the same", path, path)
+ }
+
+ if isLink {
+ if os.SameFile(sfi2, lsfi) {
+ t.Errorf("stat of opened %q file and lstat of %q should not be the same", path, path)
+ }
+ } else {
+ if !os.SameFile(sfi2, lsfi) {
+ t.Errorf("stat of opened %q file and lstat of %q should be the same", path, path)
+ }
+ }
+
+ // test os.FileInfo returned by os.Readdir
+ if len(path) > 0 && os.IsPathSeparator(path[len(path)-1]) {
+ // skip os.Readdir test of directories with slash at the end
+ return
+ }
+ parentdir := filepath.Dir(path)
+ parent, err := os.Open(parentdir)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ defer parent.Close()
+
+ fis, err := parent.Readdir(-1)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ var lsfi2 os.FileInfo
+ base := filepath.Base(path)
+ for _, fi2 := range fis {
+ if fi2.Name() == base {
+ lsfi2 = fi2
+ break
+ }
+ }
+ if lsfi2 == nil {
+ t.Errorf("failed to find %q in its parent", path)
+ return
+ }
+ lstatCheck(t, path, lsfi2)
+
+ if !os.SameFile(lsfi, lsfi2) {
+ t.Errorf("lstat of %q file in %q directory and %q should be the same", lsfi2.Name(), parentdir, path)
+ }
+}
+
+// testIsDir verifies that fi refers to directory.
+func testIsDir(t *testing.T, path string, fi os.FileInfo) {
+ t.Helper()
+ if !fi.IsDir() {
+ t.Errorf("%q should be a directory", path)
+ }
+ if fi.Mode()&os.ModeSymlink != 0 {
+ t.Errorf("%q should not be a symlink", path)
+ }
+}
+
+// testIsSymlink verifies that fi refers to symlink.
+func testIsSymlink(t *testing.T, path string, fi os.FileInfo) {
+ t.Helper()
+ if fi.IsDir() {
+ t.Errorf("%q should not be a directory", path)
+ }
+ if fi.Mode()&os.ModeSymlink == 0 {
+ t.Errorf("%q should be a symlink", path)
+ }
+}
+
+// testIsFile verifies that fi refers to file.
+func testIsFile(t *testing.T, path string, fi os.FileInfo) {
+ t.Helper()
+ if fi.IsDir() {
+ t.Errorf("%q should not be a directory", path)
+ }
+ if fi.Mode()&os.ModeSymlink != 0 {
+ t.Errorf("%q should not be a symlink", path)
+ }
+}
+
+func testDirStats(t *testing.T, path string) {
+ testStatAndLstat(t, path, false, testIsDir, testIsDir)
+}
+
+func testFileStats(t *testing.T, path string) {
+ testStatAndLstat(t, path, false, testIsFile, testIsFile)
+}
+
+func testSymlinkStats(t *testing.T, path string, isdir bool) {
+ if isdir {
+ testStatAndLstat(t, path, true, testIsDir, testIsSymlink)
+ } else {
+ testStatAndLstat(t, path, true, testIsFile, testIsSymlink)
+ }
+}
+
+func testSymlinkSameFile(t *testing.T, path, link string) {
+ pathfi, err := os.Stat(path)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ linkfi, err := os.Stat(link)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if !os.SameFile(pathfi, linkfi) {
+ t.Errorf("os.Stat(%q) and os.Stat(%q) are not the same file", path, link)
+ }
+
+ linkfi, err = os.Lstat(link)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if os.SameFile(pathfi, linkfi) {
+ t.Errorf("os.Stat(%q) and os.Lstat(%q) are the same file", path, link)
+ }
+}
+
+func TestDirAndSymlinkStats(t *testing.T) {
+ testenv.MustHaveSymlink(t)
+
+ tmpdir, err := ioutil.TempDir("", "TestDirAndSymlinkStats")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ dir := filepath.Join(tmpdir, "dir")
+ err = os.Mkdir(dir, 0777)
+ if err != nil {
+ t.Fatal(err)
+ }
+ testDirStats(t, dir)
+
+ dirlink := filepath.Join(tmpdir, "link")
+ err = os.Symlink(dir, dirlink)
+ if err != nil {
+ t.Fatal(err)
+ }
+ testSymlinkStats(t, dirlink, true)
+ testSymlinkSameFile(t, dir, dirlink)
+
+ linklink := filepath.Join(tmpdir, "linklink")
+ err = os.Symlink(dirlink, linklink)
+ if err != nil {
+ t.Fatal(err)
+ }
+ testSymlinkStats(t, linklink, true)
+ testSymlinkSameFile(t, dir, linklink)
+}
+
+func TestFileAndSymlinkStats(t *testing.T) {
+ testenv.MustHaveSymlink(t)
+
+ tmpdir, err := ioutil.TempDir("", "TestFileAndSymlinkStats")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ file := filepath.Join(tmpdir, "file")
+ err = ioutil.WriteFile(file, []byte(""), 0644)
+ if err != nil {
+ t.Fatal(err)
+ }
+ testFileStats(t, file)
+
+ filelink := filepath.Join(tmpdir, "link")
+ err = os.Symlink(file, filelink)
+ if err != nil {
+ t.Fatal(err)
+ }
+ testSymlinkStats(t, filelink, false)
+ testSymlinkSameFile(t, file, filelink)
+
+ linklink := filepath.Join(tmpdir, "linklink")
+ err = os.Symlink(filelink, linklink)
+ if err != nil {
+ t.Fatal(err)
+ }
+ testSymlinkStats(t, linklink, false)
+ testSymlinkSameFile(t, file, linklink)
+}
+
+// see issue 27225 for details
+func TestSymlinkWithTrailingSlash(t *testing.T) {
+ testenv.MustHaveSymlink(t)
+
+ tmpdir, err := ioutil.TempDir("", "TestSymlinkWithTrailingSlash")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ dir := filepath.Join(tmpdir, "dir")
+ err = os.Mkdir(dir, 0777)
+ if err != nil {
+ t.Fatal(err)
+ }
+ dirlink := filepath.Join(tmpdir, "link")
+ err = os.Symlink(dir, dirlink)
+ if err != nil {
+ t.Fatal(err)
+ }
+ dirlinkWithSlash := dirlink + string(os.PathSeparator)
+
+ if runtime.GOOS == "windows" {
+ testSymlinkStats(t, dirlinkWithSlash, true)
+ } else {
+ testDirStats(t, dirlinkWithSlash)
+ }
+
+ fi1, err := os.Stat(dir)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ fi2, err := os.Stat(dirlinkWithSlash)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if !os.SameFile(fi1, fi2) {
+ t.Errorf("os.Stat(%q) and os.Stat(%q) are not the same file", dir, dirlinkWithSlash)
+ }
+}
diff --git a/libgo/go/os/sticky_bsd.go b/libgo/go/os/sticky_bsd.go
index 6b54c75..ae2744f 100644
--- a/libgo/go/os/sticky_bsd.go
+++ b/libgo/go/os/sticky_bsd.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd netbsd openbsd solaris
package os
diff --git a/libgo/go/os/sticky_notbsd.go b/libgo/go/os/sticky_notbsd.go
index 834e79b..edb5f69 100644
--- a/libgo/go/os/sticky_notbsd.go
+++ b/libgo/go/os/sticky_notbsd.go
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !aix
// +build !darwin
// +build !dragonfly
// +build !freebsd
diff --git a/libgo/go/os/sys_aix.go b/libgo/go/os/sys_aix.go
new file mode 100644
index 0000000..53a40f2
--- /dev/null
+++ b/libgo/go/os/sys_aix.go
@@ -0,0 +1,26 @@
+// Copyright 2018 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.
+
+package os
+
+import "syscall"
+
+// gethostname syscall cannot be used because it also returns the domain.
+// Therefore, hostname is retrieve with uname syscall and the Nodename field.
+
+func hostname() (name string, err error) {
+ var u syscall.Utsname
+ if errno := syscall.Uname(&u); errno != nil {
+ return "", NewSyscallError("uname", errno)
+ }
+ b := make([]byte, len(u.Nodename))
+ i := 0
+ for ; i < len(u.Nodename); i++ {
+ if u.Nodename[i] == 0 {
+ break
+ }
+ b[i] = byte(u.Nodename[i])
+ }
+ return string(b[:i]), nil
+}
diff --git a/libgo/go/os/types.go b/libgo/go/os/types.go
index b0b7d8d..4b6c084 100644
--- a/libgo/go/os/types.go
+++ b/libgo/go/os/types.go
@@ -57,7 +57,7 @@ const (
ModeIrregular // ?: non-regular file; nothing else is known about this file
// Mask for the type bits. For regular files, none will be set.
- ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice | ModeIrregular
+ ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice | ModeCharDevice | ModeIrregular
ModePerm FileMode = 0777 // Unix permission bits
)
diff --git a/libgo/go/os/types_windows.go b/libgo/go/os/types_windows.go
index f3297c0..5e33292 100644
--- a/libgo/go/os/types_windows.go
+++ b/libgo/go/os/types_windows.go
@@ -47,6 +47,21 @@ func newFileStatFromGetFileInformationByHandle(path string, h syscall.Handle) (f
if err != nil {
return nil, &PathError{"GetFileInformationByHandle", path, err}
}
+
+ var ti windows.FILE_ATTRIBUTE_TAG_INFO
+ err = windows.GetFileInformationByHandleEx(h, windows.FileAttributeTagInfo, (*byte)(unsafe.Pointer(&ti)), uint32(unsafe.Sizeof(ti)))
+ if err != nil {
+ if errno, ok := err.(syscall.Errno); ok && errno == windows.ERROR_INVALID_PARAMETER {
+ // It appears calling GetFileInformationByHandleEx with
+ // FILE_ATTRIBUTE_TAG_INFO fails on FAT file system with
+ // ERROR_INVALID_PARAMETER. Clear ti.ReparseTag in that
+ // instance to indicate no symlinks are possible.
+ ti.ReparseTag = 0
+ } else {
+ return nil, &PathError{"GetFileInformationByHandleEx", path, err}
+ }
+ }
+
return &fileStat{
name: basename(path),
FileAttributes: d.FileAttributes,
@@ -58,6 +73,7 @@ func newFileStatFromGetFileInformationByHandle(path string, h syscall.Handle) (f
vol: d.VolumeSerialNumber,
idxhi: d.FileIndexHigh,
idxlo: d.FileIndexLow,
+ Reserved0: ti.ReparseTag,
// fileStat.path is used by os.SameFile to decide if it needs
// to fetch vol, idxhi and idxlo. But these are already set,
// so set fileStat.path to "" to prevent os.SameFile doing it again.
@@ -78,67 +94,6 @@ func newFileStatFromWin32finddata(d *syscall.Win32finddata) *fileStat {
}
}
-// newFileStatFromGetFileAttributesExOrFindFirstFile calls GetFileAttributesEx
-// and FindFirstFile to gather all required information about the provided file path pathp.
-func newFileStatFromGetFileAttributesExOrFindFirstFile(path string, pathp *uint16) (*fileStat, error) {
- // As suggested by Microsoft, use GetFileAttributes() to acquire the file information,
- // and if it's a reparse point use FindFirstFile() to get the tag:
- // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363940(v=vs.85).aspx
- // Notice that always calling FindFirstFile can create performance problems
- // (https://golang.org/issues/19922#issuecomment-300031421)
- var fa syscall.Win32FileAttributeData
- err := syscall.GetFileAttributesEx(pathp, syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&fa)))
- if err == nil && fa.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT == 0 {
- // Not a symlink.
- return &fileStat{
- FileAttributes: fa.FileAttributes,
- CreationTime: fa.CreationTime,
- LastAccessTime: fa.LastAccessTime,
- LastWriteTime: fa.LastWriteTime,
- FileSizeHigh: fa.FileSizeHigh,
- FileSizeLow: fa.FileSizeLow,
- }, nil
- }
- // GetFileAttributesEx returns ERROR_INVALID_NAME if called
- // for invalid file name like "*.txt". Do not attempt to call
- // FindFirstFile with "*.txt", because FindFirstFile will
- // succeed. So just return ERROR_INVALID_NAME instead.
- // see https://golang.org/issue/24999 for details.
- if errno, _ := err.(syscall.Errno); errno == windows.ERROR_INVALID_NAME {
- return nil, &PathError{"GetFileAttributesEx", path, err}
- }
- // We might have symlink here. But some directories also have
- // FileAttributes FILE_ATTRIBUTE_REPARSE_POINT bit set.
- // For example, OneDrive directory is like that
- // (see golang.org/issue/22579 for details).
- // So use FindFirstFile instead to distinguish directories like
- // OneDrive from real symlinks (see instructions described at
- // https://blogs.msdn.microsoft.com/oldnewthing/20100212-00/?p=14963/
- // and in particular bits about using both FileAttributes and
- // Reserved0 fields).
- var fd syscall.Win32finddata
- sh, err := syscall.FindFirstFile(pathp, &fd)
- if err != nil {
- return nil, &PathError{"FindFirstFile", path, err}
- }
- syscall.FindClose(sh)
-
- return newFileStatFromWin32finddata(&fd), nil
-}
-
-func (fs *fileStat) updatePathAndName(name string) error {
- fs.path = name
- if !isAbs(fs.path) {
- var err error
- fs.path, err = syscall.FullPath(fs.path)
- if err != nil {
- return &PathError{"FullPath", name, err}
- }
- }
- fs.name = basename(name)
- return nil
-}
-
func (fs *fileStat) isSymlink() bool {
// Use instructions described at
// https://blogs.msdn.microsoft.com/oldnewthing/20100212-00/?p=14963/
@@ -211,7 +166,13 @@ func (fs *fileStat) loadFileId() error {
if err != nil {
return err
}
- h, err := syscall.CreateFile(pathp, 0, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0)
+ attrs := uint32(syscall.FILE_FLAG_BACKUP_SEMANTICS)
+ if fs.isSymlink() {
+ // Use FILE_FLAG_OPEN_REPARSE_POINT, otherwise CreateFile will follow symlink.
+ // See https://docs.microsoft.com/en-us/windows/desktop/FileIO/symbolic-link-effects-on-file-systems-functions#createfile-and-createfiletransacted
+ attrs |= syscall.FILE_FLAG_OPEN_REPARSE_POINT
+ }
+ h, err := syscall.CreateFile(pathp, 0, 0, nil, syscall.OPEN_EXISTING, attrs, 0)
if err != nil {
return err
}
diff --git a/libgo/go/os/user/lookup.go b/libgo/go/os/user/lookup.go
index 2243a25..b36b7c0 100644
--- a/libgo/go/os/user/lookup.go
+++ b/libgo/go/os/user/lookup.go
@@ -7,6 +7,10 @@ package user
import "sync"
// Current returns the current user.
+//
+// The first call will cache the current user information.
+// Subsequent calls will return the cached value and will not reflect
+// changes to the current user.
func Current() (*User, error) {
cache.Do(func() { cache.u, cache.err = current() })
if cache.err != nil {
diff --git a/libgo/go/os/user/lookup_stubs.go b/libgo/go/os/user/lookup_stubs.go
index f7d138f..61bf1dc 100644
--- a/libgo/go/os/user/lookup_stubs.go
+++ b/libgo/go/os/user/lookup_stubs.go
@@ -19,8 +19,15 @@ func init() {
}
func current() (*User, error) {
- u := &User{
- Uid: currentUID(),
+ uid := currentUID()
+ // $USER and /etc/passwd may disagree; prefer the latter if we can get it.
+ // See issue 27524 for more information.
+ u, err := lookupUserId(uid)
+ if err == nil {
+ return u, nil
+ }
+ u = &User{
+ Uid: uid,
Gid: currentGID(),
Username: os.Getenv("USER"),
Name: "", // ignored
@@ -58,8 +65,8 @@ func current() (*User, error) {
}
func listGroups(*User) ([]string, error) {
- if runtime.GOOS == "android" {
- return nil, errors.New("user: GroupIds not implemented on Android")
+ if runtime.GOOS == "android" || runtime.GOOS == "aix" {
+ return nil, errors.New(fmt.Sprintf("user: GroupIds not implemented on %s", runtime.GOOS))
}
return nil, errors.New("user: GroupIds requires cgo")
}
diff --git a/libgo/go/os/user/lookup_unix.go b/libgo/go/os/user/lookup_unix.go
index c4e9ba1..be62f4d 100644
--- a/libgo/go/os/user/lookup_unix.go
+++ b/libgo/go/os/user/lookup_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd js,wasm !android,linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm !android,linux nacl netbsd openbsd solaris
// +build !cgo osusergo
package user
diff --git a/libgo/go/os/user/lookup_unix_test.go b/libgo/go/os/user/lookup_unix_test.go
index 02c88ab..65fe065 100644
--- a/libgo/go/os/user/lookup_unix_test.go
+++ b/libgo/go/os/user/lookup_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd !android,linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd !android,linux nacl netbsd openbsd solaris
// +build !cgo
package user
diff --git a/libgo/go/os/user/user.go b/libgo/go/os/user/user.go
index 1f733b8..c1b8101 100644
--- a/libgo/go/os/user/user.go
+++ b/libgo/go/os/user/user.go
@@ -11,7 +11,7 @@ parses /etc/passwd and /etc/group. The other is cgo-based and relies on
the standard C library (libc) routines such as getpwuid_r and getgrnam_r.
When cgo is available, cgo-based (libc-backed) code is used by default.
-This can be overriden by using osusergo build tag, which enforces
+This can be overridden by using osusergo build tag, which enforces
the pure Go implementation.
*/
package user
diff --git a/libgo/go/os/user/user_test.go b/libgo/go/os/user/user_test.go
index 8fd760e..2563077 100644
--- a/libgo/go/os/user/user_test.go
+++ b/libgo/go/os/user/user_test.go
@@ -5,33 +5,18 @@
package user
import (
- "internal/testenv"
- "os"
"runtime"
"testing"
)
func checkUser(t *testing.T) {
+ t.Helper()
if !userImplemented {
t.Skip("user: not implemented; skipping tests")
}
}
func TestCurrent(t *testing.T) {
- // The Go builders (in particular the ones using containers)
- // often have minimal environments without $HOME or $USER set,
- // which breaks Current which relies on those working as a
- // fallback.
- // TODO: we should fix that (Issue 24884) and remove these
- // workarounds.
- if testenv.Builder() != "" && runtime.GOOS != "windows" && runtime.GOOS != "plan9" {
- if os.Getenv("HOME") == "" {
- os.Setenv("HOME", "/tmp")
- }
- if os.Getenv("USER") == "" {
- os.Setenv("USER", "gobuilder")
- }
- }
u, err := Current()
if err != nil {
t.Fatalf("Current: %v (got %#v)", err, u)
@@ -108,6 +93,7 @@ func TestLookupId(t *testing.T) {
}
func checkGroup(t *testing.T) {
+ t.Helper()
if !groupImplemented {
t.Skip("user: group not implemented; skipping test")
}
diff --git a/libgo/go/os/wait_unimp.go b/libgo/go/os/wait_unimp.go
index d070604..469abf7 100644
--- a/libgo/go/os/wait_unimp.go
+++ b/libgo/go/os/wait_unimp.go
@@ -7,7 +7,7 @@
package os
// blockUntilWaitable attempts to block until a call to p.Wait will
-// succeed immediately, and returns whether it has done so.
+// succeed immediately, and reports whether it has done so.
// It does not actually call p.Wait.
// This version is used on systems that do not implement waitid,
// or where we have not implemented it yet.
diff --git a/libgo/go/os/wait_wait6.go b/libgo/go/os/wait_wait6.go
index 891f242..45bf649 100644
--- a/libgo/go/os/wait_wait6.go
+++ b/libgo/go/os/wait_wait6.go
@@ -14,7 +14,7 @@ import (
const _P_PID = 0
// blockUntilWaitable attempts to block until a call to p.Wait will
-// succeed immediately, and returns whether it has done so.
+// succeed immediately, and reports whether it has done so.
// It does not actually call p.Wait.
func (p *Process) blockUntilWaitable() (bool, error) {
var errno syscall.Errno
diff --git a/libgo/go/os/wait_waitid.go b/libgo/go/os/wait_waitid.go
index a6284aa..4bb77f9 100644
--- a/libgo/go/os/wait_waitid.go
+++ b/libgo/go/os/wait_waitid.go
@@ -18,7 +18,7 @@ import (
const _P_PID = 1
// blockUntilWaitable attempts to block until a call to p.Wait will
-// succeed immediately, and returns whether it has done so.
+// succeed immediately, and reports whether it has done so.
// It does not actually call p.Wait.
func (p *Process) blockUntilWaitable() (bool, error) {
// The waitid system call expects a pointer to a siginfo_t,