123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- // 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"
- "io/fs"
- )
- // 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 = fs.ErrInvalid // "invalid argument"
- ErrPermission = fs.ErrPermission // "permission denied"
- ErrExist = fs.ErrExist // "file already exists"
- ErrNotExist = fs.ErrNotExist // "file does not exist"
- ErrClosed = fs.ErrClosed // "file already closed"
- ErrNoDeadline = errNoDeadline() // "file type does not support deadline"
- ErrDeadlineExceeded = errDeadlineExceeded() // "i/o timeout"
- )
- func errClosed() error { return oserror.ErrClosed }
- func errNoDeadline() error { return poll.ErrNoDeadline }
- // errDeadlineExceeded returns the value for os.ErrDeadlineExceeded.
- // This error comes from the internal/poll package, which is also
- // used by package net. Doing this this way ensures that the net
- // package will return os.ErrDeadlineExceeded for an exceeded deadline,
- // as documented by net.Conn.SetDeadline, without requiring any extra
- // work in the net package and without requiring the internal/poll
- // package to import os (which it can't, because that would be circular).
- func errDeadlineExceeded() error { return poll.ErrDeadlineExceeded }
- type timeout interface {
- Timeout() bool
- }
- // PathError records an error and the operation and file path that caused it.
- type PathError = fs.PathError
- // 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.
- //
- // This function predates errors.Is. It only supports errors returned by
- // the os package. New code should use errors.Is(err, fs.ErrExist).
- 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.
- //
- // This function predates errors.Is. It only supports errors returned by
- // the os package. New code should use errors.Is(err, fs.ErrNotExist).
- 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.
- //
- // This function predates errors.Is. It only supports errors returned by
- // the os package. New code should use errors.Is(err, fs.ErrPermission).
- 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.
- //
- // This function predates errors.Is, and the notion of whether an
- // error indicates a timeout can be ambiguous. For example, the Unix
- // error EWOULDBLOCK sometimes indicates a timeout and sometimes does not.
- // New code should use errors.Is with a value appropriate to the call
- // returning the error, such as os.ErrDeadlineExceeded.
- 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 implementing Unwrap().
- 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
- }
|