summaryrefslogtreecommitdiff
path: root/libgo/go/os
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/os')
-rw-r--r--libgo/go/os/dir_unix.go2
-rw-r--r--libgo/go/os/env.go5
-rw-r--r--libgo/go/os/env_test.go26
-rw-r--r--libgo/go/os/error_plan9.go3
-rw-r--r--libgo/go/os/exec/exec.go13
-rw-r--r--libgo/go/os/exec/exec_test.go17
-rw-r--r--libgo/go/os/exec_unix.go14
-rw-r--r--libgo/go/os/exec_windows.go3
-rw-r--r--libgo/go/os/file.go9
-rw-r--r--libgo/go/os/file_plan9.go11
-rw-r--r--libgo/go/os/file_posix.go22
-rw-r--r--libgo/go/os/file_unix.go35
-rw-r--r--libgo/go/os/getwd.go24
-rw-r--r--libgo/go/os/os_test.go195
-rw-r--r--libgo/go/os/path.go16
-rw-r--r--libgo/go/os/path_test.go11
-rw-r--r--libgo/go/os/proc.go15
-rw-r--r--libgo/go/os/signal/signal_test.go6
-rw-r--r--libgo/go/os/types_windows.go3
-rw-r--r--libgo/go/os/user/lookup_stubs.go2
-rw-r--r--libgo/go/os/user/lookup_unix.go2
21 files changed, 335 insertions, 99 deletions
diff --git a/libgo/go/os/dir_unix.go b/libgo/go/os/dir_unix.go
index d353e405e54..589db852740 100644
--- a/libgo/go/os/dir_unix.go
+++ b/libgo/go/os/dir_unix.go
@@ -36,7 +36,7 @@ func (f *File) readdirnames(n int) (names []string, err error) {
if d.bufp >= d.nbuf {
d.bufp = 0
var errno error
- d.nbuf, errno = syscall.ReadDirent(f.fd, d.buf)
+ d.nbuf, errno = fixCount(syscall.ReadDirent(f.fd, d.buf))
if errno != nil {
return names, NewSyscallError("readdirent", errno)
}
diff --git a/libgo/go/os/env.go b/libgo/go/os/env.go
index db7fc72b8a4..d0494a47634 100644
--- a/libgo/go/os/env.go
+++ b/libgo/go/os/env.go
@@ -91,6 +91,11 @@ func Setenv(key, value string) error {
return nil
}
+// Unsetenv unsets a single environment variable.
+func Unsetenv(key string) error {
+ return syscall.Unsetenv(key)
+}
+
// Clearenv deletes all environment variables.
func Clearenv() {
syscall.Clearenv()
diff --git a/libgo/go/os/env_test.go b/libgo/go/os/env_test.go
index 991fa4d0578..e6180675137 100644
--- a/libgo/go/os/env_test.go
+++ b/libgo/go/os/env_test.go
@@ -7,6 +7,7 @@ package os_test
import (
. "os"
"reflect"
+ "strings"
"testing"
)
@@ -68,3 +69,28 @@ func TestConsistentEnviron(t *testing.T) {
}
}
}
+
+func TestUnsetenv(t *testing.T) {
+ const testKey = "GO_TEST_UNSETENV"
+ set := func() bool {
+ prefix := testKey + "="
+ for _, key := range Environ() {
+ if strings.HasPrefix(key, prefix) {
+ return true
+ }
+ }
+ return false
+ }
+ if err := Setenv(testKey, "1"); err != nil {
+ t.Fatalf("Setenv: %v", err)
+ }
+ if !set() {
+ t.Error("Setenv didn't set TestUnsetenv")
+ }
+ if err := Unsetenv(testKey); err != nil {
+ t.Fatalf("Unsetenv: %v", err)
+ }
+ if set() {
+ t.Fatal("Unsetenv didn't clear TestUnsetenv")
+ }
+}
diff --git a/libgo/go/os/error_plan9.go b/libgo/go/os/error_plan9.go
index 85260c82aea..001cdfcf2e3 100644
--- a/libgo/go/os/error_plan9.go
+++ b/libgo/go/os/error_plan9.go
@@ -25,7 +25,8 @@ func isNotExist(err error) bool {
case *LinkError:
err = pe.Err
}
- return contains(err.Error(), "does not exist")
+ return contains(err.Error(), "does not exist") || contains(err.Error(), "not found") ||
+ contains(err.Error(), "has been removed") || contains(err.Error(), "no parent")
}
func isPermission(err error) bool {
diff --git a/libgo/go/os/exec/exec.go b/libgo/go/os/exec/exec.go
index a70ed0d20cb..72b4905d560 100644
--- a/libgo/go/os/exec/exec.go
+++ b/libgo/go/os/exec/exec.go
@@ -55,8 +55,15 @@ type Cmd struct {
// calling process's current directory.
Dir string
- // Stdin specifies the process's standard input. If Stdin is
- // nil, the process reads from the null device (os.DevNull).
+ // Stdin specifies the process's standard input.
+ // If Stdin is nil, the process reads from the null device (os.DevNull).
+ // If Stdin is an *os.File, the process's standard input is connected
+ // directly to that file.
+ // Otherwise, during the execution of the command a separate
+ // goroutine reads from Stdin and delivers that data to the command
+ // over a pipe. In this case, Wait does not complete until the goroutine
+ // stops copying, either because it has reached the end of Stdin
+ // (EOF or a read error) or because writing to the pipe returned an error.
Stdin io.Reader
// Stdout and Stderr specify the process's standard output and error.
@@ -358,7 +365,7 @@ func (c *Cmd) Wait() error {
c.ProcessState = state
var copyError error
- for _ = range c.goroutine {
+ for range c.goroutine {
if err := <-c.errch; err != nil && copyError == nil {
copyError = err
}
diff --git a/libgo/go/os/exec/exec_test.go b/libgo/go/os/exec/exec_test.go
index 8521bfda3f9..f9ffde602ca 100644
--- a/libgo/go/os/exec/exec_test.go
+++ b/libgo/go/os/exec/exec_test.go
@@ -250,7 +250,7 @@ func TestPipeLookPathLeak(t *testing.T) {
}
func numOpenFDS(t *testing.T) (n int, lsof []byte) {
- lsof, err := exec.Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
+ lsof, err := exec.Command("lsof", "-b", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
if err != nil {
t.Skip("skipping test; error finding or running lsof")
}
@@ -262,15 +262,7 @@ var testedAlreadyLeaked = false
// basefds returns the number of expected file descriptors
// to be present in a process at start.
func basefds() uintptr {
- n := os.Stderr.Fd() + 1
-
- // Go runtime for 32-bit Plan 9 requires that /dev/bintime
- // be kept open.
- // See ../../runtime/time_plan9_386.c:/^runtime·nanotime
- if runtime.GOOS == "plan9" && runtime.GOARCH == "386" {
- n++
- }
- return n
+ return os.Stderr.Fd() + 1
}
func closeUnexpectedFds(t *testing.T, m string) {
@@ -387,8 +379,9 @@ func TestExtraFilesFDShuffle(t *testing.T) {
}
func TestExtraFiles(t *testing.T) {
- if runtime.GOOS == "windows" {
- t.Skip("no operating system support; skipping")
+ switch runtime.GOOS {
+ case "nacl", "windows":
+ t.Skipf("skipping test on %q", runtime.GOOS)
}
// Ensure that file descriptors have not already been leaked into
diff --git a/libgo/go/os/exec_unix.go b/libgo/go/os/exec_unix.go
index 1b1e3350b84..ed97f85e22f 100644
--- a/libgo/go/os/exec_unix.go
+++ b/libgo/go/os/exec_unix.go
@@ -34,18 +34,26 @@ func (p *Process) wait() (ps *ProcessState, err error) {
return ps, nil
}
+var errFinished = errors.New("os: process already finished")
+
func (p *Process) signal(sig Signal) error {
- if p.done() {
- return errors.New("os: process already finished")
- }
if p.Pid == -1 {
return errors.New("os: process already released")
}
+ if p.Pid == 0 {
+ return errors.New("os: process not initialized")
+ }
+ if p.done() {
+ return errFinished
+ }
s, ok := sig.(syscall.Signal)
if !ok {
return errors.New("os: unsupported signal type")
}
if e := syscall.Kill(p.Pid, s); e != nil {
+ if e == syscall.ESRCH {
+ return errFinished
+ }
return e
}
return nil
diff --git a/libgo/go/os/exec_windows.go b/libgo/go/os/exec_windows.go
index c4f3d4f8530..393393b2375 100644
--- a/libgo/go/os/exec_windows.go
+++ b/libgo/go/os/exec_windows.go
@@ -53,6 +53,9 @@ func terminateProcess(pid, exitcode int) error {
}
func (p *Process) signal(sig Signal) error {
+ if p.handle == uintptr(syscall.InvalidHandle) {
+ return syscall.EINVAL
+ }
if p.done() {
return errors.New("os: process already finished")
}
diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go
index b4a74580162..e12428cbe12 100644
--- a/libgo/go/os/file.go
+++ b/libgo/go/os/file.go
@@ -255,3 +255,12 @@ var lstat = Lstat
func Rename(oldpath, newpath string) error {
return rename(oldpath, newpath)
}
+
+// Many functions in package syscall return a count of -1 instead of 0.
+// Using fixCount(call()) instead of call() corrects the count.
+func fixCount(n int, err error) (int, error) {
+ if n < 0 {
+ n = 0
+ }
+ return n, err
+}
diff --git a/libgo/go/os/file_plan9.go b/libgo/go/os/file_plan9.go
index a804b819731..132594eede9 100644
--- a/libgo/go/os/file_plan9.go
+++ b/libgo/go/os/file_plan9.go
@@ -25,7 +25,8 @@ type file struct {
dirinfo *dirInfo // nil unless directory being read
}
-// Fd returns the integer Unix file descriptor referencing the open file.
+// Fd returns the integer Plan 9 file descriptor referencing the open file.
+// The file descriptor is valid only until f.Close is called or f is garbage collected.
func (f *File) Fd() uintptr {
if f == nil {
return ^(uintptr(0))
@@ -244,14 +245,14 @@ func (f *File) Sync() (err error) {
// read reads up to len(b) bytes from the File.
// It returns the number of bytes read and an error, if any.
func (f *File) read(b []byte) (n int, err error) {
- return syscall.Read(f.fd, b)
+ return fixCount(syscall.Read(f.fd, b))
}
// pread reads len(b) bytes from the File starting at byte offset off.
// It returns the number of bytes read and the error, if any.
// EOF is signaled by a zero count with err set to nil.
func (f *File) pread(b []byte, off int64) (n int, err error) {
- return syscall.Pread(f.fd, b, off)
+ return fixCount(syscall.Pread(f.fd, b, off))
}
// write writes len(b) bytes to the File.
@@ -262,7 +263,7 @@ func (f *File) write(b []byte) (n int, err error) {
if len(b) == 0 {
return 0, nil
}
- return syscall.Write(f.fd, b)
+ return fixCount(syscall.Write(f.fd, b))
}
// pwrite writes len(b) bytes to the File starting at byte offset off.
@@ -273,7 +274,7 @@ func (f *File) pwrite(b []byte, off int64) (n int, err error) {
if len(b) == 0 {
return 0, nil
}
- return syscall.Pwrite(f.fd, b, off)
+ return fixCount(syscall.Pwrite(f.fd, b, off))
}
// seek sets the offset for the next Read or Write on file to offset, interpreted
diff --git a/libgo/go/os/file_posix.go b/libgo/go/os/file_posix.go
index b3466b15cc8..fbb3b5e4d81 100644
--- a/libgo/go/os/file_posix.go
+++ b/libgo/go/os/file_posix.go
@@ -13,32 +13,12 @@ import (
func sigpipe() // implemented in package runtime
-// Link creates newname as a hard link to the oldname file.
-// If there is an error, it will be of type *LinkError.
-func Link(oldname, newname string) error {
- e := syscall.Link(oldname, newname)
- if e != nil {
- return &LinkError{"link", oldname, newname, e}
- }
- return nil
-}
-
-// Symlink creates newname as a symbolic link to oldname.
-// If there is an error, it will be of type *LinkError.
-func Symlink(oldname, newname string) error {
- e := syscall.Symlink(oldname, newname)
- if e != nil {
- return &LinkError{"symlink", oldname, newname, e}
- }
- return nil
-}
-
// Readlink returns the destination of the named symbolic link.
// If there is an error, it will be of type *PathError.
func Readlink(name string) (string, error) {
for len := 128; ; len *= 2 {
b := make([]byte, len)
- n, e := syscall.Readlink(name, b)
+ n, e := fixCount(syscall.Readlink(name, b))
if e != nil {
return "", &PathError{"readlink", name, e}
}
diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go
index 7959091995f..b25e62ff003 100644
--- a/libgo/go/os/file_unix.go
+++ b/libgo/go/os/file_unix.go
@@ -29,6 +29,7 @@ type file struct {
}
// Fd returns the integer Unix file descriptor referencing the open file.
+// The file descriptor is valid only until f.Close is called or f is garbage collected.
func (f *File) Fd() uintptr {
if f == nil {
return ^(uintptr(0))
@@ -198,7 +199,7 @@ func (f *File) read(b []byte) (n int, err error) {
if needsMaxRW && len(b) > maxRW {
b = b[:maxRW]
}
- return syscall.Read(f.fd, b)
+ return fixCount(syscall.Read(f.fd, b))
}
// pread reads len(b) bytes from the File starting at byte offset off.
@@ -208,7 +209,7 @@ func (f *File) pread(b []byte, off int64) (n int, err error) {
if needsMaxRW && len(b) > maxRW {
b = b[:maxRW]
}
- return syscall.Pread(f.fd, b, off)
+ return fixCount(syscall.Pread(f.fd, b, off))
}
// write writes len(b) bytes to the File.
@@ -219,7 +220,7 @@ func (f *File) write(b []byte) (n int, err error) {
if needsMaxRW && len(bcap) > maxRW {
bcap = bcap[:maxRW]
}
- m, err := syscall.Write(f.fd, bcap)
+ m, err := fixCount(syscall.Write(f.fd, bcap))
n += m
// If the syscall wrote some data but not all (short write)
@@ -245,7 +246,7 @@ func (f *File) pwrite(b []byte, off int64) (n int, err error) {
if needsMaxRW && len(b) > maxRW {
b = b[:maxRW]
}
- return syscall.Pwrite(f.fd, b, off)
+ return fixCount(syscall.Pwrite(f.fd, b, off))
}
// seek sets the offset for the next Read or Write on file to offset, interpreted
@@ -319,7 +320,31 @@ func basename(name string) string {
func TempDir() string {
dir := Getenv("TMPDIR")
if dir == "" {
- dir = "/tmp"
+ if runtime.GOOS == "android" {
+ dir = "/data/local/tmp"
+ } else {
+ dir = "/tmp"
+ }
}
return dir
}
+
+// Link creates newname as a hard link to the oldname file.
+// If there is an error, it will be of type *LinkError.
+func Link(oldname, newname string) error {
+ e := syscall.Link(oldname, newname)
+ if e != nil {
+ return &LinkError{"link", oldname, newname, e}
+ }
+ return nil
+}
+
+// Symlink creates newname as a symbolic link to oldname.
+// If there is an error, it will be of type *LinkError.
+func Symlink(oldname, newname string) error {
+ e := syscall.Symlink(oldname, newname)
+ if e != nil {
+ return &LinkError{"symlink", oldname, newname, e}
+ }
+ return nil
+}
diff --git a/libgo/go/os/getwd.go b/libgo/go/os/getwd.go
index a72edeaee6e..d5da53b34bf 100644
--- a/libgo/go/os/getwd.go
+++ b/libgo/go/os/getwd.go
@@ -5,6 +5,7 @@
package os
import (
+ "runtime"
"sync"
"syscall"
)
@@ -23,22 +24,16 @@ var useSyscallwd = func(error) bool { return true }
// reached via multiple paths (due to symbolic links),
// Getwd may return any one of them.
func Getwd() (dir string, err error) {
- // If the operating system provides a Getwd call, use it.
- if syscall.ImplementsGetwd {
- s, e := syscall.Getwd()
- if useSyscallwd(e) {
- return s, NewSyscallError("getwd", e)
- }
+ if runtime.GOOS == "windows" {
+ return syscall.Getwd()
}
- // Otherwise, we're trying to find our way back to ".".
+ // Clumsy but widespread kludge:
+ // if $PWD is set and matches ".", use it.
dot, err := Stat(".")
if err != nil {
return "", err
}
-
- // Clumsy but widespread kludge:
- // if $PWD is set and matches ".", use it.
dir = Getenv("PWD")
if len(dir) > 0 && dir[0] == '/' {
d, err := Stat(dir)
@@ -47,6 +42,15 @@ func Getwd() (dir string, err error) {
}
}
+ // If the operating system provides a Getwd call, use it.
+ // Otherwise, we're trying to find our way back to ".".
+ if syscall.ImplementsGetwd {
+ s, e := syscall.Getwd()
+ if useSyscallwd(e) {
+ return s, NewSyscallError("getwd", e)
+ }
+ }
+
// Apply same kludge but to cached dir instead of $PWD.
getwdCache.Lock()
dir = getwdCache.dir
diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go
index a34e328b814..7a86efac218 100644
--- a/libgo/go/os/os_test.go
+++ b/libgo/go/os/os_test.go
@@ -18,12 +18,15 @@ import (
"runtime"
"sort"
"strings"
+ "sync"
"syscall"
"testing"
"text/template"
"time"
)
+var supportsSymlinks = true
+
var dot = []string{
"dir_unix.go",
"env.go",
@@ -40,6 +43,14 @@ type sysDir struct {
var sysdir = func() (sd *sysDir) {
switch runtime.GOOS {
+ case "android":
+ sd = &sysDir{
+ "/system/etc",
+ []string{
+ "audio_policy.conf",
+ "system_fonts.xml",
+ },
+ }
case "windows":
sd = &sysDir{
Getenv("SystemRoot") + "\\system32\\drivers\\etc",
@@ -106,12 +117,27 @@ func newFile(testName string, t *testing.T) (f *File) {
// On Unix, override $TMPDIR in case the user
// has it set to an NFS-mounted directory.
dir := ""
- if runtime.GOOS != "windows" {
+ if runtime.GOOS != "android" && runtime.GOOS != "windows" {
dir = "/tmp"
}
f, err := ioutil.TempFile(dir, "_Go_"+testName)
if err != nil {
- t.Fatalf("open %s: %s", testName, err)
+ t.Fatalf("TempFile %s: %s", testName, err)
+ }
+ return
+}
+
+func newDir(testName string, t *testing.T) (name string) {
+ // Use a local file system, not NFS.
+ // On Unix, override $TMPDIR in case the user
+ // has it set to an NFS-mounted directory.
+ dir := ""
+ if runtime.GOOS != "android" && runtime.GOOS != "windows" {
+ dir = "/tmp"
+ }
+ name, err := ioutil.TempDir(dir, "_Go_"+testName)
+ if err != nil {
+ t.Fatalf("TempDir %s: %s", testName, err)
}
return
}
@@ -282,10 +308,12 @@ func TestReaddirnamesOneAtATime(t *testing.T) {
// big directory that doesn't change often.
dir := "/usr/bin"
switch runtime.GOOS {
- case "windows":
- dir = Getenv("SystemRoot") + "\\system32"
+ case "android":
+ dir = "/system/bin"
case "plan9":
dir = "/bin"
+ case "windows":
+ dir = Getenv("SystemRoot") + "\\system32"
}
file, err := Open(dir)
if err != nil {
@@ -463,7 +491,7 @@ func TestReaddirStatFailures(t *testing.T) {
func TestHardLink(t *testing.T) {
// Hardlinks are not supported under windows or Plan 9.
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+ if runtime.GOOS == "plan9" {
return
}
from, to := "hardlinktestfrom", "hardlinktestto"
@@ -496,8 +524,12 @@ func TestHardLink(t *testing.T) {
func TestSymlink(t *testing.T) {
switch runtime.GOOS {
- case "windows", "plan9", "nacl":
+ case "android", "nacl", "plan9":
t.Skipf("skipping on %s", runtime.GOOS)
+ case "windows":
+ if !supportsSymlinks {
+ t.Skipf("skipping on %s", runtime.GOOS)
+ }
}
from, to := "symlinktestfrom", "symlinktestto"
Remove(from) // Just in case.
@@ -558,8 +590,12 @@ func TestSymlink(t *testing.T) {
func TestLongSymlink(t *testing.T) {
switch runtime.GOOS {
- case "windows", "plan9", "nacl":
+ case "plan9", "nacl":
t.Skipf("skipping on %s", runtime.GOOS)
+ case "windows":
+ if !supportsSymlinks {
+ t.Skipf("skipping on %s", runtime.GOOS)
+ }
}
s := "0123456789abcdef"
// Long, but not too long: a common limit is 255.
@@ -628,8 +664,9 @@ func exec(t *testing.T, dir, cmd string, args []string, expect string) {
}
func TestStartProcess(t *testing.T) {
- if runtime.GOOS == "nacl" {
- t.Skip("skipping on nacl")
+ switch runtime.GOOS {
+ case "android", "nacl":
+ t.Skipf("skipping on %s", runtime.GOOS)
}
var dir, cmd string
@@ -731,35 +768,49 @@ func TestTruncate(t *testing.T) {
}
}
-// Use TempDir() to make sure we're on a local file system,
+// Use TempDir (via newFile) to make sure we're on a local file system,
// so that timings are not distorted by latency and caching.
// On NFS, timings can be off due to caching of meta-data on
// NFS servers (Issue 848).
func TestChtimes(t *testing.T) {
f := newFile("TestChtimes", t)
defer Remove(f.Name())
- defer f.Close()
f.Write([]byte("hello, world\n"))
f.Close()
- st, err := Stat(f.Name())
+ testChtimes(t, f.Name())
+}
+
+// Use TempDir (via newDir) to make sure we're on a local file system,
+// so that timings are not distorted by latency and caching.
+// On NFS, timings can be off due to caching of meta-data on
+// NFS servers (Issue 848).
+func TestChtimesDir(t *testing.T) {
+ name := newDir("TestChtimes", t)
+ defer RemoveAll(name)
+
+ testChtimes(t, name)
+}
+
+func testChtimes(t *testing.T, name string) {
+ st, err := Stat(name)
if err != nil {
- t.Fatalf("Stat %s: %s", f.Name(), err)
+ t.Fatalf("Stat %s: %s", name, err)
}
preStat := st
// Move access and modification time back a second
at := Atime(preStat)
mt := preStat.ModTime()
- err = Chtimes(f.Name(), at.Add(-time.Second), mt.Add(-time.Second))
+ err = Chtimes(name, at.Add(-time.Second), mt.Add(-time.Second))
if err != nil {
- t.Fatalf("Chtimes %s: %s", f.Name(), err)
+ t.Fatalf("Chtimes %s: %s", name, err)
}
- st, err = Stat(f.Name())
+ st, err = Stat(name)
if err != nil {
- t.Fatalf("second Stat %s: %s", f.Name(), err)
+ t.Fatalf("second Stat %s: %s", name, err)
}
postStat := st
@@ -788,12 +839,16 @@ func TestChdirAndGetwd(t *testing.T) {
t.Fatalf("Open .: %s", err)
}
// These are chosen carefully not to be symlinks on a Mac
- // (unlike, say, /var, /etc, and /tmp).
- dirs := []string{"/", "/usr/bin"}
- // /usr/bin does not usually exist on Plan 9.
- if runtime.GOOS == "plan9" {
+ // (unlike, say, /var, /etc), except /tmp, which we handle below.
+ dirs := []string{"/", "/usr/bin", "/tmp"}
+ // /usr/bin does not usually exist on Plan 9 or Android.
+ switch runtime.GOOS {
+ case "android":
+ dirs = []string{"/", "/system/bin"}
+ case "plan9":
dirs = []string{"/", "/usr"}
}
+ oldwd := Getenv("PWD")
for mode := 0; mode < 2; mode++ {
for _, d := range dirs {
if mode == 0 {
@@ -807,7 +862,11 @@ func TestChdirAndGetwd(t *testing.T) {
err = fd1.Chdir()
fd1.Close()
}
+ if d == "/tmp" {
+ Setenv("PWD", "/tmp")
+ }
pwd, err1 := Getwd()
+ Setenv("PWD", oldwd)
err2 := fd.Chdir()
if err2 != nil {
// We changed the current directory and cannot go back.
@@ -910,6 +969,12 @@ func TestOpenError(t *testing.T) {
syscallErrStr := perr.Err.Error()
expectedErrStr := strings.Replace(tt.error.Error(), "file ", "", 1)
if !strings.HasSuffix(syscallErrStr, expectedErrStr) {
+ // Some Plan 9 file servers incorrectly return
+ // EACCES rather than EISDIR when a directory is
+ // opened for write.
+ if tt.error == syscall.EISDIR && strings.HasSuffix(syscallErrStr, syscall.EACCES.Error()) {
+ continue
+ }
t.Errorf("Open(%q, %d) = _, %q; want suffix %q", tt.path, tt.mode, syscallErrStr, expectedErrStr)
}
continue
@@ -970,9 +1035,9 @@ func run(t *testing.T, cmd []string) string {
func TestHostname(t *testing.T) {
// There is no other way to fetch hostname on windows, but via winapi.
- // On Plan 9 it is can be taken from #c/sysname as Hostname() does.
+ // On Plan 9 it can be taken from #c/sysname as Hostname() does.
switch runtime.GOOS {
- case "windows", "plan9", "nacl":
+ case "android", "nacl", "plan9", "windows":
t.Skipf("skipping on %s", runtime.GOOS)
}
@@ -1233,8 +1298,9 @@ func TestReadAtEOF(t *testing.T) {
func testKillProcess(t *testing.T, processKiller func(p *Process)) {
t.Skip("gccgo does not have a go command")
- if runtime.GOOS == "nacl" {
- t.Skip("skipping on nacl")
+ switch runtime.GOOS {
+ case "android", "nacl":
+ t.Skipf("skipping on %s", runtime.GOOS)
}
dir, err := ioutil.TempDir("", "go-build")
@@ -1292,6 +1358,36 @@ func TestKillStartProcess(t *testing.T) {
})
}
+func TestGetppid(t *testing.T) {
+ switch runtime.GOOS {
+ case "nacl":
+ t.Skip("skipping on nacl")
+ case "plan9":
+ // TODO: golang.org/issue/8206
+ t.Skipf("skipping test on plan9; see issue 8206")
+ }
+
+ if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
+ fmt.Print(Getppid())
+ Exit(0)
+ }
+
+ cmd := osexec.Command(Args[0], "-test.run=TestGetppid")
+ cmd.Env = append(Environ(), "GO_WANT_HELPER_PROCESS=1")
+
+ // verify that Getppid() from the forked process reports our process id
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Failed to spawn child process: %v %q", err, string(output))
+ }
+
+ childPpid := string(output)
+ ourPid := fmt.Sprintf("%d", Getpid())
+ if childPpid != ourPid {
+ t.Fatalf("Child process reports parent process id '%v', expected '%v'", childPpid, ourPid)
+ }
+}
+
func TestKillFindProcess(t *testing.T) {
testKillProcess(t, func(p *Process) {
p2, err := FindProcess(p.Pid)
@@ -1336,3 +1432,52 @@ func TestNilFileMethods(t *testing.T) {
}
}
}
+
+func mkdirTree(t *testing.T, root string, level, max int) {
+ if level >= max {
+ return
+ }
+ level++
+ for i := 'a'; i < 'c'; i++ {
+ dir := filepath.Join(root, string(i))
+ if err := Mkdir(dir, 0700); err != nil {
+ t.Fatal(err)
+ }
+ mkdirTree(t, dir, level, max)
+ }
+}
+
+// Test that simultaneous RemoveAll do not report an error.
+// As long as it gets removed, we should be happy.
+func TestRemoveAllRace(t *testing.T) {
+ if runtime.GOOS == "windows" {
+ // Windows has very strict rules about things like
+ // removing directories while someone else has
+ // them open. The racing doesn't work out nicely
+ // like it does on Unix.
+ t.Skip("skipping on windows")
+ }
+
+ n := runtime.GOMAXPROCS(16)
+ defer runtime.GOMAXPROCS(n)
+ root, err := ioutil.TempDir("", "issue")
+ if err != nil {
+ t.Fatal(err)
+ }
+ mkdirTree(t, root, 1, 6)
+ hold := make(chan struct{})
+ var wg sync.WaitGroup
+ for i := 0; i < 4; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ <-hold
+ err := RemoveAll(root)
+ if err != nil {
+ t.Errorf("unexpected error: %T, %q", err, err)
+ }
+ }()
+ }
+ close(hold) // let workers race to remove root
+ wg.Wait()
+}
diff --git a/libgo/go/os/path.go b/libgo/go/os/path.go
index 02a77ec8051..84a3be3348f 100644
--- a/libgo/go/os/path.go
+++ b/libgo/go/os/path.go
@@ -17,7 +17,7 @@ import (
// If path is already a directory, MkdirAll does nothing
// and returns nil.
func MkdirAll(path string, perm FileMode) error {
- // If path exists, stop with success or error.
+ // Fast path: if we can tell whether path is a directory or file, stop with success or error.
dir, err := Stat(path)
if err == nil {
if dir.IsDir() {
@@ -26,7 +26,7 @@ func MkdirAll(path string, perm FileMode) error {
return &PathError{"mkdir", path, syscall.ENOTDIR}
}
- // Doesn't already exist; make sure parent does.
+ // Slow path: make sure parent exists and then call Mkdir for path.
i := len(path)
for i > 0 && IsPathSeparator(path[i-1]) { // Skip trailing path separator.
i--
@@ -45,7 +45,7 @@ func MkdirAll(path string, perm FileMode) error {
}
}
- // Now parent exists, try to create.
+ // Parent now exists; invoke Mkdir and use its result.
err = Mkdir(path, perm)
if err != nil {
// Handle arguments like "foo/." by
@@ -66,7 +66,7 @@ func MkdirAll(path string, perm FileMode) error {
func RemoveAll(path string) error {
// Simple case: if Remove works, we're done.
err := Remove(path)
- if err == nil {
+ if err == nil || IsNotExist(err) {
return nil
}
@@ -86,6 +86,11 @@ func RemoveAll(path string) error {
// Directory.
fd, err := Open(path)
if err != nil {
+ if IsNotExist(err) {
+ // Race. It was deleted between the Lstat and Open.
+ // Return nil per RemoveAll's docs.
+ return nil
+ }
return err
}
@@ -116,6 +121,9 @@ func RemoveAll(path string) error {
// Remove directory.
err1 := Remove(path)
+ if err1 == nil || IsNotExist(err1) {
+ return nil
+ }
if err == nil {
err = err1
}
diff --git a/libgo/go/os/path_test.go b/libgo/go/os/path_test.go
index 3af21cde9af..6f24a43132a 100644
--- a/libgo/go/os/path_test.go
+++ b/libgo/go/os/path_test.go
@@ -168,8 +168,12 @@ func TestRemoveAll(t *testing.T) {
func TestMkdirAllWithSymlink(t *testing.T) {
switch runtime.GOOS {
- case "nacl", "plan9", "windows":
+ case "nacl", "plan9":
t.Skipf("skipping on %s", runtime.GOOS)
+ case "windows":
+ if !supportsSymlinks {
+ t.Skipf("skipping on %s", runtime.GOOS)
+ }
}
tmpDir, err := ioutil.TempDir("", "TestMkdirAllWithSymlink-")
@@ -198,8 +202,9 @@ func TestMkdirAllWithSymlink(t *testing.T) {
}
func TestMkdirAllAtSlash(t *testing.T) {
- if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
- return
+ switch runtime.GOOS {
+ case "android", "plan9", "windows":
+ t.Skipf("skipping on %s", runtime.GOOS)
}
RemoveAll("/_go_os_test")
err := MkdirAll("/_go_os_test/dir", 0777)
diff --git a/libgo/go/os/proc.go b/libgo/go/os/proc.go
index 38c436ec54d..774f09900ec 100644
--- a/libgo/go/os/proc.go
+++ b/libgo/go/os/proc.go
@@ -6,11 +6,24 @@
package os
-import "syscall"
+import (
+ "runtime"
+ "syscall"
+)
// Args hold the command-line arguments, starting with the program name.
var Args []string
+func init() {
+ if runtime.GOOS == "windows" {
+ // Initialized in exec_windows.go.
+ return
+ }
+ Args = runtime_args()
+}
+
+func runtime_args() []string // in package runtime
+
// Getuid returns the numeric user id of the caller.
func Getuid() int { return syscall.Getuid() }
diff --git a/libgo/go/os/signal/signal_test.go b/libgo/go/os/signal/signal_test.go
index 076fe3f93bd..22337a72d4b 100644
--- a/libgo/go/os/signal/signal_test.go
+++ b/libgo/go/os/signal/signal_test.go
@@ -125,7 +125,7 @@ func TestStop(t *testing.T) {
if sig != syscall.SIGHUP || *sendUncaughtSighup == 1 {
syscall.Kill(syscall.Getpid(), sig)
}
- time.Sleep(10 * time.Millisecond)
+ time.Sleep(100 * time.Millisecond)
// Ask for signal
c := make(chan os.Signal, 1)
@@ -140,7 +140,7 @@ func TestStop(t *testing.T) {
select {
case s := <-c:
t.Fatalf("unexpected signal %v", s)
- case <-time.After(10 * time.Millisecond):
+ case <-time.After(100 * time.Millisecond):
// nothing to read - good
}
@@ -154,7 +154,7 @@ func TestStop(t *testing.T) {
select {
case s := <-c:
t.Fatalf("unexpected signal %v", s)
- case <-time.After(10 * time.Millisecond):
+ case <-time.After(100 * time.Millisecond):
// nothing to read - good
}
}
diff --git a/libgo/go/os/types_windows.go b/libgo/go/os/types_windows.go
index 38901681e67..7b2e54698c3 100644
--- a/libgo/go/os/types_windows.go
+++ b/libgo/go/os/types_windows.go
@@ -39,6 +39,9 @@ func (fs *fileStat) Mode() (m FileMode) {
} else {
m |= 0666
}
+ if fs.sys.FileAttributes&syscall.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
+ m |= ModeSymlink
+ }
return m
}
diff --git a/libgo/go/os/user/lookup_stubs.go b/libgo/go/os/user/lookup_stubs.go
index 86f0e6e645a..4fb0e3c6edd 100644
--- a/libgo/go/os/user/lookup_stubs.go
+++ b/libgo/go/os/user/lookup_stubs.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 !cgo,!windows,!plan9
+// +build !cgo,!windows,!plan9 android
package user
diff --git a/libgo/go/os/user/lookup_unix.go b/libgo/go/os/user/lookup_unix.go
index 0db08067201..64f4576f69e 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 linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris
// +build cgo
package user