diff options
Diffstat (limited to 'src/os')
| -rw-r--r-- | src/os/env.go | 5 | ||||
| -rw-r--r-- | src/os/env_test.go | 26 | ||||
| -rw-r--r-- | src/os/error_plan9.go | 2 | ||||
| -rw-r--r-- | src/os/exec/exec_test.go | 5 | ||||
| -rw-r--r-- | src/os/os_test.go | 50 | ||||
| -rw-r--r-- | src/os/path.go | 10 | ||||
| -rw-r--r-- | src/os/proc.go | 15 | ||||
| -rw-r--r-- | src/os/signal/signal_test.go | 6 |
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 } } |
