diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-10-03 05:27:36 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-10-03 05:27:36 +0000 |
commit | bd2e46c8255fad4e75e589b3286ead560e910b39 (patch) | |
tree | 4f194bdb2e9edcc69ef2ab0dfb4aab15ca259267 /libgo/go/os | |
parent | bed6238ce677ba18a672a58bc077cec6de47f8d3 (diff) | |
download | gcc-bd2e46c8255fad4e75e589b3286ead560e910b39.zip gcc-bd2e46c8255fad4e75e589b3286ead560e910b39.tar.gz gcc-bd2e46c8255fad4e75e589b3286ead560e910b39.tar.bz2 |
libgo: Update to Go 1.0.3.
From-SVN: r192025
Diffstat (limited to 'libgo/go/os')
-rw-r--r-- | libgo/go/os/error_plan9.go | 21 | ||||
-rw-r--r-- | libgo/go/os/error_posix.go | 21 | ||||
-rw-r--r-- | libgo/go/os/error_test.go | 27 | ||||
-rw-r--r-- | libgo/go/os/error_windows.go | 21 | ||||
-rw-r--r-- | libgo/go/os/exec.go | 11 | ||||
-rw-r--r-- | libgo/go/os/exec/exec.go | 8 | ||||
-rw-r--r-- | libgo/go/os/exec/exec_test.go | 72 | ||||
-rw-r--r-- | libgo/go/os/exec_plan9.go | 4 | ||||
-rw-r--r-- | libgo/go/os/exec_posix.go | 5 | ||||
-rw-r--r-- | libgo/go/os/exec_unix.go | 4 | ||||
-rw-r--r-- | libgo/go/os/exec_windows.go | 4 | ||||
-rw-r--r-- | libgo/go/os/file_posix.go | 11 | ||||
-rw-r--r-- | libgo/go/os/file_unix.go | 13 | ||||
-rw-r--r-- | libgo/go/os/os_test.go | 10 | ||||
-rw-r--r-- | libgo/go/os/types.go | 2 |
15 files changed, 197 insertions, 37 deletions
diff --git a/libgo/go/os/error_plan9.go b/libgo/go/os/error_plan9.go index 3c9dfb0..85260c8 100644 --- a/libgo/go/os/error_plan9.go +++ b/libgo/go/os/error_plan9.go @@ -5,21 +5,36 @@ package os func isExist(err error) bool { - if pe, ok := err.(*PathError); ok { + switch pe := err.(type) { + case nil: + return false + case *PathError: + err = pe.Err + case *LinkError: err = pe.Err } return contains(err.Error(), " exists") } func isNotExist(err error) bool { - if pe, ok := err.(*PathError); ok { + switch pe := err.(type) { + case nil: + return false + case *PathError: + err = pe.Err + case *LinkError: err = pe.Err } return contains(err.Error(), "does not exist") } func isPermission(err error) bool { - if pe, ok := err.(*PathError); ok { + switch pe := err.(type) { + case nil: + return false + case *PathError: + err = pe.Err + case *LinkError: err = pe.Err } return contains(err.Error(), "permission denied") diff --git a/libgo/go/os/error_posix.go b/libgo/go/os/error_posix.go index 1685c1f..81b626a 100644 --- a/libgo/go/os/error_posix.go +++ b/libgo/go/os/error_posix.go @@ -9,21 +9,36 @@ package os import "syscall" func isExist(err error) bool { - if pe, ok := err.(*PathError); ok { + switch pe := err.(type) { + case nil: + return false + case *PathError: + err = pe.Err + case *LinkError: err = pe.Err } return err == syscall.EEXIST || err == ErrExist } func isNotExist(err error) bool { - if pe, ok := err.(*PathError); ok { + switch pe := err.(type) { + case nil: + return false + case *PathError: + err = pe.Err + case *LinkError: err = pe.Err } return err == syscall.ENOENT || err == ErrNotExist } func isPermission(err error) bool { - if pe, ok := err.(*PathError); ok { + switch pe := err.(type) { + case nil: + return false + case *PathError: + err = pe.Err + case *LinkError: err = pe.Err } return err == syscall.EACCES || err == syscall.EPERM || err == ErrPermission diff --git a/libgo/go/os/error_test.go b/libgo/go/os/error_test.go index 42f846f..054bb3f 100644 --- a/libgo/go/os/error_test.go +++ b/libgo/go/os/error_test.go @@ -79,3 +79,30 @@ func checkErrorPredicate(predName string, pred func(error) bool, err error) stri } return "" } + +var isExistTests = []struct { + err error + is bool + isnot bool +}{ + {&os.PathError{Err: os.ErrInvalid}, false, false}, + {&os.PathError{Err: os.ErrPermission}, false, false}, + {&os.PathError{Err: os.ErrExist}, true, false}, + {&os.PathError{Err: os.ErrNotExist}, false, true}, + {&os.LinkError{Err: os.ErrInvalid}, false, false}, + {&os.LinkError{Err: os.ErrPermission}, false, false}, + {&os.LinkError{Err: os.ErrExist}, true, false}, + {&os.LinkError{Err: os.ErrNotExist}, false, true}, + {nil, false, false}, +} + +func TestIsExist(t *testing.T) { + for _, tt := range isExistTests { + if is := os.IsExist(tt.err); is != tt.is { + t.Errorf("os.IsExist(%T %v) = %v, want %v", tt.err, tt.err, is, tt.is) + } + if isnot := os.IsNotExist(tt.err); isnot != tt.isnot { + t.Errorf("os.IsNotExist(%T %v) = %v, want %v", tt.err, tt.err, isnot, tt.isnot) + } + } +} diff --git a/libgo/go/os/error_windows.go b/libgo/go/os/error_windows.go index fbb0d4f3..83db6c0 100644 --- a/libgo/go/os/error_windows.go +++ b/libgo/go/os/error_windows.go @@ -7,7 +7,12 @@ package os import "syscall" func isExist(err error) bool { - if pe, ok := err.(*PathError); ok { + switch pe := err.(type) { + case nil: + return false + case *PathError: + err = pe.Err + case *LinkError: err = pe.Err } return err == syscall.ERROR_ALREADY_EXISTS || @@ -15,7 +20,12 @@ func isExist(err error) bool { } func isNotExist(err error) bool { - if pe, ok := err.(*PathError); ok { + switch pe := err.(type) { + case nil: + return false + case *PathError: + err = pe.Err + case *LinkError: err = pe.Err } return err == syscall.ERROR_FILE_NOT_FOUND || @@ -23,7 +33,12 @@ func isNotExist(err error) bool { } func isPermission(err error) bool { - if pe, ok := err.(*PathError); ok { + switch pe := err.(type) { + case nil: + return false + case *PathError: + err = pe.Err + case *LinkError: err = pe.Err } return err == syscall.ERROR_ACCESS_DENIED || err == ErrPermission diff --git a/libgo/go/os/exec.go b/libgo/go/os/exec.go index 531b87c..6681acf 100644 --- a/libgo/go/os/exec.go +++ b/libgo/go/os/exec.go @@ -6,6 +6,7 @@ package os import ( "runtime" + "sync/atomic" "syscall" ) @@ -13,7 +14,7 @@ import ( type Process struct { Pid int handle uintptr - done bool // process has been successfully waited on + isdone uint32 // process has been successfully waited on, non zero if true } func newProcess(pid int, handle uintptr) *Process { @@ -22,6 +23,14 @@ func newProcess(pid int, handle uintptr) *Process { return p } +func (p *Process) setDone() { + atomic.StoreUint32(&p.isdone, 1) +} + +func (p *Process) done() bool { + return atomic.LoadUint32(&p.isdone) > 0 +} + // ProcAttr holds the attributes that will be applied to a new process // started by StartProcess. type ProcAttr struct { diff --git a/libgo/go/os/exec/exec.go b/libgo/go/os/exec/exec.go index 9a8e181..c4907cd 100644 --- a/libgo/go/os/exec/exec.go +++ b/libgo/go/os/exec/exec.go @@ -16,7 +16,7 @@ import ( "syscall" ) -// Error records the name of a binary that failed to be be executed +// Error records the name of a binary that failed to be executed // and the reason it failed. type Error struct { Name string @@ -143,6 +143,9 @@ func (c *Cmd) argv() []string { func (c *Cmd) stdin() (f *os.File, err error) { if c.Stdin == nil { f, err = os.Open(os.DevNull) + if err != nil { + return + } c.closeAfterStart = append(c.closeAfterStart, f) return } @@ -182,6 +185,9 @@ func (c *Cmd) stderr() (f *os.File, err error) { func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err error) { if w == nil { f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0) + if err != nil { + return + } c.closeAfterStart = append(c.closeAfterStart, f) return } diff --git a/libgo/go/os/exec/exec_test.go b/libgo/go/os/exec/exec_test.go index 52f4bce..27ebb60 100644 --- a/libgo/go/os/exec/exec_test.go +++ b/libgo/go/os/exec/exec_test.go @@ -167,6 +167,18 @@ func TestExtraFiles(t *testing.T) { } defer ln.Close() + // Make sure duplicated fds don't leak to the child. + f, err := ln.(*net.TCPListener).File() + if err != nil { + t.Fatal(err) + } + defer f.Close() + ln2, err := net.FileListener(f) + if err != nil { + t.Fatal(err) + } + defer ln2.Close() + // Force TLS root certs to be loaded (which might involve // cgo), to make sure none of that potential C code leaks fds. ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -203,6 +215,56 @@ func TestExtraFiles(t *testing.T) { } } +func TestExtraFilesRace(t *testing.T) { + if runtime.GOOS == "windows" { + t.Logf("no operating system support; skipping") + return + } + listen := func() net.Listener { + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + return ln + } + listenerFile := func(ln net.Listener) *os.File { + f, err := ln.(*net.TCPListener).File() + if err != nil { + t.Fatal(err) + } + return f + } + runCommand := func(c *Cmd, out chan<- string) { + bout, err := c.CombinedOutput() + if err != nil { + out <- "ERROR:" + err.Error() + } else { + out <- string(bout) + } + } + + for i := 0; i < 10; i++ { + la := listen() + ca := helperCommand("describefiles") + ca.ExtraFiles = []*os.File{listenerFile(la)} + lb := listen() + cb := helperCommand("describefiles") + cb.ExtraFiles = []*os.File{listenerFile(lb)} + ares := make(chan string) + bres := make(chan string) + go runCommand(ca, ares) + go runCommand(cb, bres) + if got, want := <-ares, fmt.Sprintf("fd3: listener %s\n", la.Addr()); got != want { + t.Errorf("iteration %d, process A got:\n%s\nwant:\n%s\n", i, got, want) + } + if got, want := <-bres, fmt.Sprintf("fd3: listener %s\n", lb.Addr()); got != want { + t.Errorf("iteration %d, process B got:\n%s\nwant:\n%s\n", i, got, want) + } + la.Close() + lb.Close() + } +} + // TestHelperProcess isn't a real test. It's used as a helper process // for TestParameterRun. func TestHelperProcess(*testing.T) { @@ -318,6 +380,16 @@ func TestHelperProcess(*testing.T) { case "exit": n, _ := strconv.Atoi(args[0]) os.Exit(n) + case "describefiles": + for fd := uintptr(3); fd < 25; fd++ { + f := os.NewFile(fd, fmt.Sprintf("fd-%d", fd)) + ln, err := net.FileListener(f) + if err == nil { + fmt.Printf("fd%d: listener %s\n", fd, ln.Addr()) + ln.Close() + } + } + os.Exit(0) default: fmt.Fprintf(os.Stderr, "Unknown command %q\n", cmd) os.Exit(2) diff --git a/libgo/go/os/exec_plan9.go b/libgo/go/os/exec_plan9.go index 41cc8c2..01f06e2 100644 --- a/libgo/go/os/exec_plan9.go +++ b/libgo/go/os/exec_plan9.go @@ -38,7 +38,7 @@ func (note Plan9Note) String() string { } func (p *Process) signal(sig Signal) error { - if p.done { + if p.done() { return errors.New("os: process already finished") } @@ -76,7 +76,7 @@ func (p *Process) wait() (ps *ProcessState, err error) { } if waitmsg.Pid == p.Pid { - p.done = true + p.setDone() break } } diff --git a/libgo/go/os/exec_posix.go b/libgo/go/os/exec_posix.go index 70351cf..40fd0fd 100644 --- a/libgo/go/os/exec_posix.go +++ b/libgo/go/os/exec_posix.go @@ -11,9 +11,10 @@ import ( ) func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) { - // Double-check existence of the directory we want + // If there is no SysProcAttr (ie. no Chroot or changed + // UID/GID), double-check existence of the directory we want // to chdir into. We can make the error clearer this way. - if attr != nil && attr.Dir != "" { + if attr != nil && attr.Sys == nil && attr.Dir != "" { if _, err := Stat(attr.Dir); err != nil { pe := err.(*PathError) pe.Op = "chdir" diff --git a/libgo/go/os/exec_unix.go b/libgo/go/os/exec_unix.go index ecfe535..fa3ba8a 100644 --- a/libgo/go/os/exec_unix.go +++ b/libgo/go/os/exec_unix.go @@ -24,7 +24,7 @@ func (p *Process) wait() (ps *ProcessState, err error) { return nil, NewSyscallError("wait", e) } if pid1 != 0 { - p.done = true + p.setDone() } ps = &ProcessState{ pid: pid1, @@ -35,7 +35,7 @@ func (p *Process) wait() (ps *ProcessState, err error) { } func (p *Process) signal(sig Signal) error { - if p.done { + if p.done() { return errors.New("os: process already finished") } s, ok := sig.(syscall.Signal) diff --git a/libgo/go/os/exec_windows.go b/libgo/go/os/exec_windows.go index 5beca4a..4aa2ade 100644 --- a/libgo/go/os/exec_windows.go +++ b/libgo/go/os/exec_windows.go @@ -32,7 +32,7 @@ func (p *Process) wait() (ps *ProcessState, err error) { if e != nil { return nil, NewSyscallError("GetProcessTimes", e) } - p.done = true + p.setDone() // 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 @@ -43,7 +43,7 @@ func (p *Process) wait() (ps *ProcessState, err error) { } func (p *Process) signal(sig Signal) error { - if p.done { + if p.done() { return errors.New("os: process already finished") } if sig == Kill { diff --git a/libgo/go/os/file_posix.go b/libgo/go/os/file_posix.go index 073bd56..1ba3293 100644 --- a/libgo/go/os/file_posix.go +++ b/libgo/go/os/file_posix.go @@ -13,17 +13,6 @@ import ( func sigpipe() // implemented in package runtime -func epipecheck(file *File, e error) { - if e == syscall.EPIPE { - file.nepipe++ - if file.nepipe >= 10 { - sigpipe() - } - } else { - file.nepipe = 0 - } -} - // 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 { diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go index b8fb2e2..f677dbb 100644 --- a/libgo/go/os/file_unix.go +++ b/libgo/go/os/file_unix.go @@ -8,6 +8,7 @@ package os import ( "runtime" + "sync/atomic" "syscall" ) @@ -24,7 +25,7 @@ type file struct { fd int name string dirinfo *dirInfo // nil unless directory being read - nepipe int // number of consecutive EPIPE in Write + nepipe int32 // number of consecutive EPIPE in Write } // Fd returns the integer Unix file descriptor referencing the open file. @@ -52,6 +53,16 @@ type dirInfo struct { dir *syscall.DIR // from opendir } +func epipecheck(file *File, e error) { + if e == syscall.EPIPE { + if atomic.AddInt32(&file.nepipe, 1) >= 10 { + sigpipe() + } + } else { + atomic.StoreInt32(&file.nepipe, 0) + } +} + // DevNull is the name of the operating system's ``null device.'' // On Unix-like systems, it is "/dev/null"; on Windows, "NUL". const DevNull = "/dev/null" diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go index 8d3f677..5046e60 100644 --- a/libgo/go/os/os_test.go +++ b/libgo/go/os/os_test.go @@ -67,10 +67,10 @@ var sysdir = func() (sd *sysDir) { func size(name string, t *testing.T) int64 { file, err := Open(name) - defer file.Close() if err != nil { t.Fatal("open failed:", err) } + defer file.Close() var buf [100]byte len := 0 for { @@ -132,10 +132,10 @@ func TestStat(t *testing.T) { func TestFstat(t *testing.T) { path := sfdir + "/" + sfname file, err1 := Open(path) - defer file.Close() if err1 != nil { t.Fatal("open failed:", err1) } + defer file.Close() dir, err2 := file.Stat() if err2 != nil { t.Fatal("fstat failed:", err2) @@ -187,10 +187,10 @@ func TestRead0(t *testing.T) { func testReaddirnames(dir string, contents []string, t *testing.T) { file, err := Open(dir) - defer file.Close() if err != nil { t.Fatalf("open %q failed: %v", dir, err) } + defer file.Close() s, err2 := file.Readdirnames(-1) if err2 != nil { t.Fatalf("readdirnames %q failed: %v", dir, err2) @@ -216,10 +216,10 @@ func testReaddirnames(dir string, contents []string, t *testing.T) { func testReaddir(dir string, contents []string, t *testing.T) { file, err := Open(dir) - defer file.Close() if err != nil { t.Fatalf("open %q failed: %v", dir, err) } + defer file.Close() s, err2 := file.Readdir(-1) if err2 != nil { t.Fatalf("readdir %q failed: %v", dir, err2) @@ -283,10 +283,10 @@ func TestReaddirnamesOneAtATime(t *testing.T) { dir = "/bin" } file, err := Open(dir) - defer file.Close() if err != nil { t.Fatalf("open %q failed: %v", dir, err) } + defer file.Close() all, err1 := file.Readdirnames(-1) if err1 != nil { t.Fatalf("readdirnames %q failed: %v", dir, err1) diff --git a/libgo/go/os/types.go b/libgo/go/os/types.go index 0c95c9c..ecb5787 100644 --- a/libgo/go/os/types.go +++ b/libgo/go/os/types.go @@ -12,7 +12,7 @@ import ( // Getpagesize returns the underlying system's memory page size. func Getpagesize() int { return syscall.Getpagesize() } -// A FileInfo describes a file and is returned by Stat and Lstat +// A FileInfo describes a file and is returned by Stat and Lstat. type FileInfo interface { Name() string // base name of the file Size() int64 // length in bytes for regular files; system-dependent for others |