diff options
author | Ondřej Surý <ondrej@sury.org> | 2012-03-26 16:50:58 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2012-03-26 16:50:58 +0200 |
commit | 519725bb3c075ee2462c929f5997cb068e18466a (patch) | |
tree | 5b162e8488ad147a645048c073577821b4a2bee9 /src/pkg/os | |
parent | 842623c5dd2819d980ca9c58048d6bc6ed82475f (diff) | |
download | golang-upstream-weekly/2012.03.22.tar.gz |
Imported Upstream version 2012.03.22upstream-weekly/2012.03.22
Diffstat (limited to 'src/pkg/os')
-rw-r--r-- | src/pkg/os/error.go | 18 | ||||
-rw-r--r-- | src/pkg/os/error_plan9.go | 9 | ||||
-rw-r--r-- | src/pkg/os/error_posix.go | 14 | ||||
-rw-r--r-- | src/pkg/os/error_test.go | 81 | ||||
-rw-r--r-- | src/pkg/os/error_windows.go | 30 | ||||
-rw-r--r-- | src/pkg/os/exec/exec.go | 2 | ||||
-rw-r--r-- | src/pkg/os/file_unix.go | 16 | ||||
-rw-r--r-- | src/pkg/os/os_test.go | 19 | ||||
-rw-r--r-- | src/pkg/os/stat_windows.go | 24 | ||||
-rw-r--r-- | src/pkg/os/types.go | 2 |
10 files changed, 195 insertions, 20 deletions
diff --git a/src/pkg/os/error.go b/src/pkg/os/error.go index e0b83b5c2..b88e49400 100644 --- a/src/pkg/os/error.go +++ b/src/pkg/os/error.go @@ -42,3 +42,21 @@ func NewSyscallError(syscall string, err error) error { } return &SyscallError{syscall, err} } + +// IsExist returns whether the error is known to report that a file or directory +// already exists. It is satisfied by ErrExist as well as some syscall errors. +func IsExist(err error) bool { + return isExist(err) +} + +// IsNotExist returns whether the error is known to report that a file or directory +// does not exist. It is satisfied by ErrNotExist as well as some syscall errors. +func IsNotExist(err error) bool { + return isNotExist(err) +} + +// IsPermission returns whether the error is known to report that permission is denied. +// It is satisfied by ErrPermission as well as some syscall errors. +func IsPermission(err error) bool { + return isPermission(err) +} diff --git a/src/pkg/os/error_plan9.go b/src/pkg/os/error_plan9.go index 159d685e7..3c9dfb0b1 100644 --- a/src/pkg/os/error_plan9.go +++ b/src/pkg/os/error_plan9.go @@ -4,24 +4,21 @@ package os -// IsExist returns whether the error is known to report that a file already exists. -func IsExist(err error) bool { +func isExist(err error) bool { if pe, ok := err.(*PathError); ok { err = pe.Err } return contains(err.Error(), " exists") } -// IsNotExist returns whether the error is known to report that a file does not exist. -func IsNotExist(err error) bool { +func isNotExist(err error) bool { if pe, ok := err.(*PathError); ok { err = pe.Err } return contains(err.Error(), "does not exist") } -// IsPermission returns whether the error is known to report that permission is denied. -func IsPermission(err error) bool { +func isPermission(err error) bool { if pe, ok := err.(*PathError); ok { err = pe.Err } diff --git a/src/pkg/os/error_posix.go b/src/pkg/os/error_posix.go index 74b75d112..1685c1f21 100644 --- a/src/pkg/os/error_posix.go +++ b/src/pkg/os/error_posix.go @@ -2,33 +2,27 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd linux netbsd openbsd windows +// +build darwin freebsd linux netbsd openbsd package os import "syscall" -// IsExist returns whether the error is known to report that a file already exists. -// It is satisfied by ErrExist as well as some syscall errors. -func IsExist(err error) bool { +func isExist(err error) bool { if pe, ok := err.(*PathError); ok { err = pe.Err } return err == syscall.EEXIST || err == ErrExist } -// IsNotExist returns whether the error is known to report that a file does not exist. -// It is satisfied by ErrNotExist as well as some syscall errors. -func IsNotExist(err error) bool { +func isNotExist(err error) bool { if pe, ok := err.(*PathError); ok { err = pe.Err } return err == syscall.ENOENT || err == ErrNotExist } -// IsPermission returns whether the error is known to report that permission is denied. -// It is satisfied by ErrPermission as well as some syscall errors. -func IsPermission(err error) bool { +func isPermission(err error) bool { if pe, ok := err.(*PathError); ok { err = pe.Err } diff --git a/src/pkg/os/error_test.go b/src/pkg/os/error_test.go new file mode 100644 index 000000000..42f846fa3 --- /dev/null +++ b/src/pkg/os/error_test.go @@ -0,0 +1,81 @@ +// Copyright 2012 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" + "testing" +) + +func TestErrIsExist(t *testing.T) { + f, err := ioutil.TempFile("", "_Go_ErrIsExist") + if err != nil { + t.Fatalf("open ErrIsExist tempfile: %s", err) + return + } + defer os.Remove(f.Name()) + defer f.Close() + f2, err := os.OpenFile(f.Name(), os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) + if err == nil { + f2.Close() + t.Fatal("Open should have failed") + return + } + if s := checkErrorPredicate("os.IsExist", os.IsExist, err); s != "" { + t.Fatal(s) + return + } +} + +func testErrNotExist(name string) string { + f, err := os.Open(name) + if err == nil { + f.Close() + return "Open should have failed" + } + if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err); s != "" { + return s + } + + err = os.Chdir(name) + if err == nil { + return "Chdir should have failed" + } + if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err); s != "" { + return s + } + return "" +} + +func TestErrIsNotExist(t *testing.T) { + tmpDir, err := ioutil.TempDir("", "_Go_ErrIsNotExist") + if err != nil { + t.Fatalf("create ErrIsNotExist tempdir: %s", err) + return + } + defer os.RemoveAll(tmpDir) + + name := filepath.Join(tmpDir, "NotExists") + if s := testErrNotExist(name); s != "" { + t.Fatal(s) + return + } + + name = filepath.Join(name, "NotExists2") + if s := testErrNotExist(name); s != "" { + t.Fatal(s) + return + } +} + +func checkErrorPredicate(predName string, pred func(error) bool, err error) string { + if !pred(err) { + return fmt.Sprintf("%s does not work as expected for %#v", predName, err) + } + return "" +} diff --git a/src/pkg/os/error_windows.go b/src/pkg/os/error_windows.go new file mode 100644 index 000000000..5d692b073 --- /dev/null +++ b/src/pkg/os/error_windows.go @@ -0,0 +1,30 @@ +// Copyright 2012 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" + +func isExist(err error) bool { + if pe, ok := err.(*PathError); ok { + err = pe.Err + } + return err == syscall.ERROR_ALREADY_EXISTS || + err == syscall.ERROR_FILE_EXISTS || err == ErrExist +} + +func isNotExist(err error) bool { + if pe, ok := err.(*PathError); ok { + err = pe.Err + } + return err == syscall.ERROR_FILE_NOT_FOUND || + err == syscall.ERROR_PATH_NOT_FOUND || err == ErrNotExist +} + +func isPermission(err error) bool { + if pe, ok := err.(*PathError); ok { + err = pe.Err + } + return err == ErrPermission +} diff --git a/src/pkg/os/exec/exec.go b/src/pkg/os/exec/exec.go index ebe92a9fb..bbd04902b 100644 --- a/src/pkg/os/exec/exec.go +++ b/src/pkg/os/exec/exec.go @@ -59,7 +59,7 @@ type Cmd struct { // If either is nil, Run connects the corresponding file descriptor // to the null device (os.DevNull). // - // If Stdout and Stderr are are the same writer, at most one + // If Stdout and Stderr are the same writer, at most one // goroutine at a time will call Write. Stdout io.Writer Stderr io.Writer diff --git a/src/pkg/os/file_unix.go b/src/pkg/os/file_unix.go index 6aa0280f4..6271c3189 100644 --- a/src/pkg/os/file_unix.go +++ b/src/pkg/os/file_unix.go @@ -173,7 +173,21 @@ func (f *File) pread(b []byte, off int64) (n int, err error) { // write writes len(b) bytes to the File. // It returns the number of bytes written and an error, if any. func (f *File) write(b []byte) (n int, err error) { - return syscall.Write(f.fd, b) + for { + m, err := syscall.Write(f.fd, b) + n += m + + // If the syscall wrote some data but not all (short write) + // or it returned EINTR, then assume it stopped early for + // reasons that are uninteresting to the caller, and try again. + if 0 < m && m < len(b) || err == syscall.EINTR { + b = b[m:] + continue + } + + return n, err + } + panic("not reached") } // pwrite writes len(b) bytes to the File starting at byte offset off. diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go index d1e241f00..dec80cc09 100644 --- a/src/pkg/os/os_test.go +++ b/src/pkg/os/os_test.go @@ -1047,3 +1047,22 @@ func TestSameFile(t *testing.T) { t.Errorf("files should be different") } } + +func TestDevNullFile(t *testing.T) { + f, err := Open(DevNull) + if err != nil { + t.Fatalf("Open(%s): %v", DevNull, err) + } + defer f.Close() + fi, err := f.Stat() + if err != nil { + t.Fatalf("Stat(%s): %v", DevNull, err) + } + name := filepath.Base(DevNull) + if fi.Name() != name { + t.Fatalf("wrong file name have %v want %v", fi.Name(), name) + } + if fi.Size() != 0 { + t.Fatalf("wrong file size have %d want 0", fi.Size()) + } +} diff --git a/src/pkg/os/stat_windows.go b/src/pkg/os/stat_windows.go index 19e215e93..75351c805 100644 --- a/src/pkg/os/stat_windows.go +++ b/src/pkg/os/stat_windows.go @@ -21,6 +21,9 @@ func (file *File) Stat() (fi FileInfo, err error) { // I don't know any better way to do that for directory return Stat(file.name) } + if file.name == DevNull { + return statDevNull() + } var d syscall.ByHandleFileInformation e := syscall.GetFileInformationByHandle(syscall.Handle(file.fd), &d) if e != nil { @@ -41,6 +44,9 @@ func Stat(name string) (fi FileInfo, err error) { if len(name) == 0 { return nil, &PathError{"Stat", name, syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)} } + if name == DevNull { + return statDevNull() + } var d syscall.Win32FileAttributeData e := syscall.GetFileAttributesEx(syscall.StringToUTF16Ptr(name), syscall.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&d))) if e != nil { @@ -69,6 +75,22 @@ func Lstat(name string) (fi FileInfo, err error) { return Stat(name) } +// statDevNull return FileInfo structure describing DevNull file ("NUL"). +// It creates invented data, since none of windows api will return +// that information. +func statDevNull() (fi FileInfo, err error) { + return &fileStat{ + name: DevNull, + mode: ModeDevice | ModeCharDevice | 0666, + sys: &winSys{ + // hopefully this will work for SameFile + vol: 0, + idxhi: 0, + idxlo: 0, + }, + }, nil +} + // basename removes trailing slashes and the leading // directory name and drive letter from path name. func basename(name string) string { @@ -199,7 +221,7 @@ func (s *winSys) loadFileId() error { } s.Lock() defer s.Unlock() - h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(s.path), syscall.GENERIC_READ, syscall.FILE_SHARE_READ, nil, syscall.OPEN_EXISTING, 0, 0) + h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(s.path), 0, 0, nil, syscall.OPEN_EXISTING, syscall.FILE_FLAG_BACKUP_SEMANTICS, 0) if e != nil { return e } diff --git a/src/pkg/os/types.go b/src/pkg/os/types.go index c7c5199be..01dddf50d 100644 --- a/src/pkg/os/types.go +++ b/src/pkg/os/types.go @@ -15,7 +15,7 @@ func Getpagesize() int { return syscall.Getpagesize() } // 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 + Size() int64 // length in bytes for regular files; system-dependent for others Mode() FileMode // file mode bits ModTime() time.Time // modification time IsDir() bool // abbreviation for Mode().IsDir() |