aboutsummaryrefslogtreecommitdiff
path: root/src/os
diff options
context:
space:
mode:
Diffstat (limited to 'src/os')
-rw-r--r--src/os/env.go5
-rw-r--r--src/os/env_test.go26
-rw-r--r--src/os/error_plan9.go2
-rw-r--r--src/os/exec/exec_test.go5
-rw-r--r--src/os/os_test.go50
-rw-r--r--src/os/path.go10
-rw-r--r--src/os/proc.go15
-rw-r--r--src/os/signal/signal_test.go6
8 files changed, 111 insertions, 8 deletions
diff --git a/src/os/env.go b/src/os/env.go
index db7fc72b8a..d0494a4763 100644
--- a/src/os/env.go
+++ b/src/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/src/os/env_test.go b/src/os/env_test.go
index 991fa4d057..e618067513 100644
--- a/src/os/env_test.go
+++ b/src/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/src/os/error_plan9.go b/src/os/error_plan9.go
index 62d4e420e4..45cd747923 100644
--- a/src/os/error_plan9.go
+++ b/src/os/error_plan9.go
@@ -25,7 +25,7 @@ func isNotExist(err error) bool {
case *LinkError:
err = pe.Err
}
- return contains(err.Error(), "does not exist") || contains(err.Error(), "not found")
+ return contains(err.Error(), "does not exist") || contains(err.Error(), "not found") || contains(err.Error(), "has been removed")
}
func isPermission(err error) bool {
diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go
index 6f77ac38ae..5fd439b8bb 100644
--- a/src/os/exec/exec_test.go
+++ b/src/os/exec/exec_test.go
@@ -383,8 +383,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/src/os/os_test.go b/src/os/os_test.go
index 0224c9b01d..973cc3a7bf 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -18,6 +18,7 @@ import (
"runtime"
"sort"
"strings"
+ "sync"
"syscall"
"testing"
"text/template"
@@ -1403,3 +1404,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/src/os/path.go b/src/os/path.go
index 02a77ec805..24a3415b46 100644
--- a/src/os/path.go
+++ b/src/os/path.go
@@ -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/src/os/proc.go b/src/os/proc.go
index 38c436ec54..774f09900e 100644
--- a/src/os/proc.go
+++ b/src/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/src/os/signal/signal_test.go b/src/os/signal/signal_test.go
index 076fe3f93b..22337a72d4 100644
--- a/src/os/signal/signal_test.go
+++ b/src/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
}
}