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