Black Lives Matter. Support the Equal Justice Initiative.

Source file src/os/error.go

Documentation: os

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

View as plain text