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