Source file src/os/error.go

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package os
     6  
     7  import (
     8  	"internal/oserror"
     9  	"internal/poll"
    10  	"io/fs"
    11  )
    12  
    13  // Portable analogs of some common system call errors.
    14  //
    15  // Errors returned from this package may be tested against these errors
    16  // with errors.Is.
    17  var (
    18  	// ErrInvalid indicates an invalid argument.
    19  	// Methods on File will return this error when the receiver is nil.
    20  	ErrInvalid = fs.ErrInvalid // "invalid argument"
    21  
    22  	ErrPermission = fs.ErrPermission // "permission denied"
    23  	ErrExist      = fs.ErrExist      // "file already exists"
    24  	ErrNotExist   = fs.ErrNotExist   // "file does not exist"
    25  	ErrClosed     = fs.ErrClosed     // "file already closed"
    26  
    27  	ErrNoDeadline       = errNoDeadline()       // "file type does not support deadline"
    28  	ErrDeadlineExceeded = errDeadlineExceeded() // "i/o timeout"
    29  )
    30  
    31  func errClosed() error     { return oserror.ErrClosed }
    32  func errNoDeadline() error { return poll.ErrNoDeadline }
    33  
    34  // errDeadlineExceeded returns the value for os.ErrDeadlineExceeded.
    35  // This error comes from the internal/poll package, which is also
    36  // used by package net. Doing this this way ensures that the net
    37  // package will return os.ErrDeadlineExceeded for an exceeded deadline,
    38  // as documented by net.Conn.SetDeadline, without requiring any extra
    39  // work in the net package and without requiring the internal/poll
    40  // package to import os (which it can't, because that would be circular).
    41  func errDeadlineExceeded() error { return poll.ErrDeadlineExceeded }
    42  
    43  type timeout interface {
    44  	Timeout() bool
    45  }
    46  
    47  // PathError records an error and the operation and file path that caused it.
    48  type PathError = fs.PathError
    49  
    50  // SyscallError records an error from a specific system call.
    51  type SyscallError struct {
    52  	Syscall string
    53  	Err     error
    54  }
    55  
    56  func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err.Error() }
    57  
    58  func (e *SyscallError) Unwrap() error { return e.Err }
    59  
    60  // Timeout reports whether this error represents a timeout.
    61  func (e *SyscallError) Timeout() bool {
    62  	t, ok := e.Err.(timeout)
    63  	return ok && t.Timeout()
    64  }
    65  
    66  // NewSyscallError returns, as an error, a new SyscallError
    67  // with the given system call name and error details.
    68  // As a convenience, if err is nil, NewSyscallError returns nil.
    69  func NewSyscallError(syscall string, err error) error {
    70  	if err == nil {
    71  		return nil
    72  	}
    73  	return &SyscallError{syscall, err}
    74  }
    75  
    76  // IsExist returns a boolean indicating whether the error is known to report
    77  // that a file or directory already exists. It is satisfied by ErrExist as
    78  // well as some syscall errors.
    79  //
    80  // This function predates errors.Is. It only supports errors returned by
    81  // the os package. New code should use errors.Is(err, fs.ErrExist).
    82  func IsExist(err error) bool {
    83  	return underlyingErrorIs(err, ErrExist)
    84  }
    85  
    86  // IsNotExist returns a boolean indicating whether the error is known to
    87  // report that a file or directory does not exist. It is satisfied by
    88  // ErrNotExist as well as some syscall errors.
    89  //
    90  // This function predates errors.Is. It only supports errors returned by
    91  // the os package. New code should use errors.Is(err, fs.ErrNotExist).
    92  func IsNotExist(err error) bool {
    93  	return underlyingErrorIs(err, ErrNotExist)
    94  }
    95  
    96  // IsPermission returns a boolean indicating whether the error is known to
    97  // report that permission is denied. It is satisfied by ErrPermission as well
    98  // as some syscall errors.
    99  //
   100  // This function predates errors.Is. It only supports errors returned by
   101  // the os package. New code should use errors.Is(err, fs.ErrPermission).
   102  func IsPermission(err error) bool {
   103  	return underlyingErrorIs(err, ErrPermission)
   104  }
   105  
   106  // IsTimeout returns a boolean indicating whether the error is known
   107  // to report that a timeout occurred.
   108  //
   109  // This function predates errors.Is, and the notion of whether an
   110  // error indicates a timeout can be ambiguous. For example, the Unix
   111  // error EWOULDBLOCK sometimes indicates a timeout and sometimes does not.
   112  // New code should use errors.Is with a value appropriate to the call
   113  // returning the error, such as os.ErrDeadlineExceeded.
   114  func IsTimeout(err error) bool {
   115  	terr, ok := underlyingError(err).(timeout)
   116  	return ok && terr.Timeout()
   117  }
   118  
   119  func underlyingErrorIs(err, target error) bool {
   120  	// Note that this function is not errors.Is:
   121  	// underlyingError only unwraps the specific error-wrapping types
   122  	// that it historically did, not all errors implementing Unwrap().
   123  	err = underlyingError(err)
   124  	if err == target {
   125  		return true
   126  	}
   127  	// To preserve prior behavior, only examine syscall errors.
   128  	e, ok := err.(syscallErrorType)
   129  	return ok && e.Is(target)
   130  }
   131  
   132  // underlyingError returns the underlying error for known os error types.
   133  func underlyingError(err error) error {
   134  	switch err := err.(type) {
   135  	case *PathError:
   136  		return err.Err
   137  	case *LinkError:
   138  		return err.Err
   139  	case *SyscallError:
   140  		return err.Err
   141  	}
   142  	return err
   143  }
   144  

View as plain text