| // 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. |
| |
| package os |
| |
| import ( |
| "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 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" |
| 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 errNoDeadline() error { return poll.ErrNoDeadline } |
| |
| type timeout interface { |
| Timeout() bool |
| } |
| |
| // PathError records an error and the operation and file path that caused it. |
| type PathError struct { |
| Op string |
| Path string |
| Err error |
| } |
| |
| func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() } |
| |
| func (e *PathError) Unwrap() error { return e.Err } |
| |
| // Timeout reports whether this error represents a timeout. |
| func (e *PathError) Timeout() bool { |
| t, ok := e.Err.(timeout) |
| return ok && t.Timeout() |
| } |
| |
| // SyscallError records an error from a specific system call. |
| type SyscallError struct { |
| Syscall string |
| Err error |
| } |
| |
| 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) |
| return ok && t.Timeout() |
| } |
| |
| // NewSyscallError returns, as an error, a new SyscallError |
| // with the given system call name and error details. |
| // As a convenience, if err is nil, NewSyscallError returns nil. |
| func NewSyscallError(syscall string, err error) error { |
| if err == nil { |
| return nil |
| } |
| return &SyscallError{syscall, err} |
| } |
| |
| // IsExist returns a boolean indicating 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 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 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 underlyingErrorIs(err, ErrPermission) |
| } |
| |
| // IsTimeout returns a boolean indicating whether the error is known |
| // to report that a timeout occurred. |
| func IsTimeout(err error) bool { |
| terr, ok := underlyingError(err).(timeout) |
| 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 |
| } |
| // To preserve prior behavior, only examine syscall errors. |
| e, ok := err.(syscallErrorType) |
| return ok && e.Is(target) |
| } |
| |
| // underlyingError returns the underlying error for known os error types. |
| func underlyingError(err error) error { |
| switch err := err.(type) { |
| case *PathError: |
| return err.Err |
| case *LinkError: |
| return err.Err |
| case *SyscallError: |
| return err.Err |
| } |
| return err |
| } |