want: "fallback:" +
"\n somefile.go:123" +
"\n - file does not exist:" +
- "\n os.init" +
- "\n .+/os/error.go:\\d\\d",
+ "\n .*" +
+ "\n .+.go:\\d+",
regexp: true,
}, {
err: &wrapped{"outer",
// End of linear dependency definitions.
// Operating system access.
- "syscall": {"L0", "internal/race", "internal/syscall/windows/sysdll", "syscall/js", "unicode/utf16"},
+ "syscall": {"L0", "internal/oserror", "internal/race", "internal/syscall/windows/sysdll", "syscall/js", "unicode/utf16"},
"syscall/js": {"L0"},
+ "internal/oserror": {"L0"},
"internal/syscall/unix": {"L0", "syscall"},
"internal/syscall/windows": {"L0", "syscall", "internal/syscall/windows/sysdll"},
"internal/syscall/windows/registry": {"L0", "syscall", "internal/syscall/windows/sysdll", "unicode/utf16"},
"internal/poll": {"L0", "internal/race", "syscall", "time", "unicode/utf16", "unicode/utf8", "internal/syscall/windows"},
"internal/testlog": {"L0"},
- "os": {"L1", "os", "syscall", "time", "internal/poll", "internal/syscall/windows", "internal/syscall/unix", "internal/testlog"},
+ "os": {"L1", "os", "syscall", "time", "internal/oserror", "internal/poll", "internal/syscall/windows", "internal/syscall/unix", "internal/testlog"},
"path/filepath": {"L2", "os", "syscall", "internal/syscall/windows"},
"io/ioutil": {"L2", "os", "path/filepath", "time"},
"os/exec": {"L2", "os", "context", "path/filepath", "syscall"},
--- /dev/null
+// Copyright 2019 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 oserror defines errors values used in the os package.
+//
+// These types are defined here to permit the syscall package to reference them.
+package oserror
+
+import "errors"
+
+var (
+ ErrInvalid = errors.New("invalid argument")
+ ErrPermission = errors.New("permission denied")
+ ErrExist = errors.New("file already exists")
+ ErrNotExist = errors.New("file does not exist")
+ ErrClosed = errors.New("file already closed")
+ ErrTemporary = errors.New("temporary error")
+ ErrTimeout = errors.New("deadline exceeded")
+)
package os
import (
- "errors"
+ "internal/oserror"
"internal/poll"
)
// Portable analogs of some common system call errors.
+//
+// Errors returned from this package may be tested against these errors
+// with errors.Is.
var (
- ErrInvalid = errors.New("invalid argument") // methods on File will return this error when the receiver is nil
- ErrPermission = errors.New("permission denied")
- ErrExist = errors.New("file already exists")
- ErrNotExist = errors.New("file does not exist")
- ErrClosed = errors.New("file already closed")
- ErrNoDeadline = poll.ErrNoDeadline
+ // ErrInvalid indicates an invalid argument.
+ // Methods on File will return this error when the receiver is nil.
+ ErrInvalid = errInvalid() // "invalid argument"
+
+ ErrPermission = errPermission() // "permission denied"
+ ErrExist = errExist() // "file already exists"
+ ErrNotExist = errNotExist() // "file does not exist"
+ ErrClosed = errClosed() // "file already closed"
+ ErrTimeout = errTimeout() // "deadline exceeded"
+ ErrNoDeadline = errNoDeadline() // "file type does not support deadline"
)
+func errInvalid() error { return oserror.ErrInvalid }
+func errPermission() error { return oserror.ErrPermission }
+func errExist() error { return oserror.ErrExist }
+func errNotExist() error { return oserror.ErrNotExist }
+func errClosed() error { return oserror.ErrClosed }
+func errTimeout() error { return oserror.ErrTimeout }
+func errNoDeadline() error { return poll.ErrNoDeadline }
+
type timeout interface {
Timeout() bool
}
func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err.Error() }
+func (e *SyscallError) Unwrap() error { return e.Err }
+
// Timeout reports whether this error represents a timeout.
func (e *SyscallError) Timeout() bool {
t, ok := e.Err.(timeout)
// 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)
+ return underlyingErrorIs(err, ErrExist)
}
// IsNotExist returns a boolean indicating 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)
+ return underlyingErrorIs(err, ErrNotExist)
}
// IsPermission returns a boolean indicating 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)
+ return underlyingErrorIs(err, ErrPermission)
}
// IsTimeout returns a boolean indicating whether the error is known
return ok && terr.Timeout()
}
+func underlyingErrorIs(err, target error) bool {
+ // Note that this function is not errors.Is:
+ // underlyingError only unwraps the specific error-wrapping types
+ // that it historically did, not all errors.Wrapper implementations.
+ err = underlyingError(err)
+ if err == target {
+ return true
+ }
+ e, ok := err.(interface{ Is(error) bool })
+ return ok && e.Is(target)
+}
+
// underlyingError returns the underlying error for known os error types.
func underlyingError(err error) error {
switch err := err.(type) {
+++ /dev/null
-// Copyright 2011 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
-
-func isExist(err error) bool {
- return checkErrMessageContent(err, "exists", "is a directory")
-}
-
-func isNotExist(err error) bool {
- return checkErrMessageContent(err, "does not exist", "not found",
- "has been removed", "no parent")
-}
-
-func isPermission(err error) bool {
- return checkErrMessageContent(err, "permission denied")
-}
-
-// checkErrMessageContent checks if err message contains one of msgs.
-func checkErrMessageContent(err error, msgs ...string) bool {
- if err == nil {
- return false
- }
- err = underlyingError(err)
- for _, msg := range msgs {
- if contains(err.Error(), msg) {
- return true
- }
- }
- return false
-}
-
-// contains is a local version of strings.Contains. It knows len(sep) > 1.
-func contains(s, sep string) bool {
- n := len(sep)
- c := sep[0]
- for i := 0; i+n <= len(s); i++ {
- if s[i] == c && s[i:i+n] == sep {
- return true
- }
- }
- return false
-}
t.Fatal("Open should have failed")
return
}
- if s := checkErrorPredicate("os.IsExist", os.IsExist, err); s != "" {
+ if s := checkErrorPredicate("os.IsExist", os.IsExist, err, os.ErrExist); s != "" {
t.Fatal(s)
return
}
f.Close()
return "Open should have failed"
}
- if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err); s != "" {
+ if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err, os.ErrNotExist); s != "" {
return s
}
if err == nil {
return "Chdir should have failed"
}
- if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err); s != "" {
+ if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err, os.ErrNotExist); s != "" {
return s
}
return ""
}
}
-func checkErrorPredicate(predName string, pred func(error) bool, err error) string {
+func checkErrorPredicate(predName string, pred func(error) bool, err, target error) string {
if !pred(err) {
return fmt.Sprintf("%s does not work as expected for %#v", predName, err)
}
+ if !errors.Is(err, target) {
+ return fmt.Sprintf("errors.Is(%#v, %#v) = false, want true", err, target)
+ }
return ""
}
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 is := errors.Is(tt.err, os.ErrExist); is != tt.is {
+ t.Errorf("errors.Is(%T %v, os.ErrExist) = %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)
}
+ if isnot := errors.Is(tt.err, os.ErrNotExist); isnot != tt.isnot {
+ t.Errorf("errors.Is(%T %v, os.ErrNotExist) = %v, want %v", tt.err, tt.err, isnot, tt.isnot)
+ }
}
}
if got := os.IsPermission(tt.err); got != tt.want {
t.Errorf("os.IsPermission(%#v) = %v; want %v", tt.err, got, tt.want)
}
+ if got := errors.Is(tt.err, os.ErrPermission); got != tt.want {
+ t.Errorf("errors.Is(%#v, os.ErrPermission) = %v; want %v", tt.err, got, tt.want)
+ }
}
}
+++ /dev/null
-// Copyright 2009 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.
-
-// +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
-
-package os
-
-import "syscall"
-
-func isExist(err error) bool {
- err = underlyingError(err)
- return err == syscall.EEXIST || err == syscall.ENOTEMPTY || err == ErrExist
-}
-
-func isNotExist(err error) bool {
- err = underlyingError(err)
- return err == syscall.ENOENT || err == ErrNotExist
-}
-
-func isPermission(err error) bool {
- err = underlyingError(err)
- return err == syscall.EACCES || err == syscall.EPERM || err == ErrPermission
-}
+++ /dev/null
-// 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 {
- err = underlyingError(err)
- return err == syscall.ERROR_ALREADY_EXISTS ||
- err == syscall.ERROR_DIR_NOT_EMPTY ||
- err == syscall.ERROR_FILE_EXISTS || err == ErrExist
-}
-
-const _ERROR_BAD_NETPATH = syscall.Errno(53)
-
-func isNotExist(err error) bool {
- err = underlyingError(err)
- return err == syscall.ERROR_FILE_NOT_FOUND ||
- err == _ERROR_BAD_NETPATH ||
- err == syscall.ERROR_PATH_NOT_FOUND || err == ErrNotExist
-}
-
-func isPermission(err error) bool {
- err = underlyingError(err)
- return err == syscall.ERROR_ACCESS_DENIED || err == ErrPermission
-}
return e.Op + " " + e.Old + " " + e.New + ": " + e.Err.Error()
}
+func (e *LinkError) Unwrap() error {
+ return e.Err
+}
+
// Read reads up to len(b) bytes from the File.
// It returns the number of bytes read and any error encountered.
// At end of file, Read returns 0, io.EOF.
package syscall
import (
+ "internal/oserror"
"sync"
"unsafe"
)
return "errno " + itoa(int(e))
}
+func (e Errno) Is(target error) bool {
+ switch target {
+ case oserror.ErrTemporary:
+ return e.Temporary()
+ case oserror.ErrTimeout:
+ return e.Timeout()
+ case oserror.ErrPermission:
+ return e == EACCES || e == EPERM
+ case oserror.ErrExist:
+ return e == EEXIST || e == ENOTEMPTY
+ case oserror.ErrNotExist:
+ return e == ENOENT
+ }
+ return false
+}
+
func (e Errno) Temporary() bool {
return e == EINTR || e == EMFILE || e.Timeout()
}
package syscall
import (
+ "internal/oserror"
"sync"
"unsafe"
)
return "errno " + itoa(int(e))
}
+func (e Errno) Is(target error) bool {
+ switch target {
+ case oserror.ErrTemporary:
+ return e.Temporary()
+ case oserror.ErrTimeout:
+ return e.Timeout()
+ case oserror.ErrPermission:
+ return e == EACCES || e == EPERM
+ case oserror.ErrExist:
+ return e == EEXIST || e == ENOTEMPTY
+ case oserror.ErrNotExist:
+ return e == ENOENT
+ }
+ return false
+}
+
func (e Errno) Temporary() bool {
return e == EINTR || e == EMFILE || e.Timeout()
}
package syscall
-import "unsafe"
+import (
+ "internal/oserror"
+ "unsafe"
+)
const ImplementsGetwd = true
const bitSize16 = 2
// NewError converts s to an ErrorString, which satisfies the Error interface.
func NewError(s string) error { return ErrorString(s) }
+func (e ErrorString) Is(target error) bool {
+ switch target {
+ case oserror.ErrTemporary:
+ return e.Temporary()
+ case oserror.ErrTimeout:
+ return e.Timeout()
+ case oserror.ErrPermission:
+ return checkErrMessageContent(e, "permission denied")
+ case oserror.ErrExist:
+ return checkErrMessageContent(e, "exists", "is a directory")
+ case oserror.ErrNotExist:
+ return checkErrMessageContent(e, "does not exist", "not found",
+ "has been removed", "no parent")
+ }
+ return false
+}
+
+// checkErrMessageContent checks if err message contains one of msgs.
+func checkErrMessageContent(e ErrorString, msgs ...string) bool {
+ for _, msg := range msgs {
+ if contains(string(e), msg) {
+ return true
+ }
+ }
+ return false
+}
+
+// contains is a local version of strings.Contains. It knows len(sep) > 1.
+func contains(s, sep string) bool {
+ n := len(sep)
+ c := sep[0]
+ for i := 0; i+n <= len(s); i++ {
+ if s[i] == c && s[i:i+n] == sep {
+ return true
+ }
+ }
+ return false
+}
+
func (e ErrorString) Temporary() bool {
return e == EINTR || e == EMFILE || e.Timeout()
}
package syscall
import (
+ "internal/oserror"
"internal/race"
"runtime"
"sync"
return "errno " + itoa(int(e))
}
+func (e Errno) Is(target error) bool {
+ switch target {
+ case oserror.ErrTemporary:
+ return e.Temporary()
+ case oserror.ErrTimeout:
+ return e.Timeout()
+ case oserror.ErrPermission:
+ return e == EACCES || e == EPERM
+ case oserror.ErrExist:
+ return e == EEXIST || e == ENOTEMPTY
+ case oserror.ErrNotExist:
+ return e == ENOENT
+ }
+ return false
+}
+
func (e Errno) Temporary() bool {
return e == EINTR || e == EMFILE || e.Timeout()
}
import (
errorspkg "errors"
+ "internal/oserror"
"internal/race"
"runtime"
"sync"
return string(utf16.Decode(b[:n]))
}
+const _ERROR_BAD_NETPATH = Errno(53)
+
+func (e Errno) Is(target error) bool {
+ switch target {
+ case oserror.ErrTemporary:
+ return e.Temporary()
+ case oserror.ErrTimeout:
+ return e.Timeout()
+ case oserror.ErrPermission:
+ return e == ERROR_ACCESS_DENIED
+ case oserror.ErrExist:
+ return e == ERROR_ALREADY_EXISTS ||
+ e == ERROR_DIR_NOT_EMPTY ||
+ e == ERROR_FILE_EXISTS
+ case oserror.ErrNotExist:
+ return e == ERROR_FILE_NOT_FOUND ||
+ e == _ERROR_BAD_NETPATH ||
+ e == ERROR_PATH_NOT_FOUND
+ }
+ return false
+}
+
func (e Errno) Temporary() bool {
return e == EINTR || e == EMFILE || e.Timeout()
}