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 "errors"
9 "io/fs"
10 "syscall"
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 // Note that these are exported for use in the Filesystem interface.
28 ErrUnsupported = errors.New("operation not supported")
29 ErrNotImplemented = errors.New("operation not implemented")
30 )
31 32 // The following code is copied from the official implementation.
33 // src/internal/poll/fd.go
34 35 // ErrNoDeadline is returned when a request is made to set a deadline
36 // on a file type that does not use the poller.
37 var ErrNoDeadline = errors.New("file type does not support deadline")
38 39 // ErrDeadlineExceeded is returned for an expired deadline.
40 // This is exported by the os package as os.ErrDeadlineExceeded.
41 var ErrDeadlineExceeded error = &DeadlineExceededError{}
42 43 // DeadlineExceededError is returned for an expired deadline.
44 type DeadlineExceededError struct{}
45 46 // Implement the net.Error interface.
47 // The string is "i/o timeout" because that is what was returned
48 // by earlier Go versions. Changing it may break programs that
49 // match on error strings.
50 func (e *DeadlineExceededError) Error() string { return "i/o timeout" }
51 func (e *DeadlineExceededError) Timeout() bool { return true }
52 func (e *DeadlineExceededError) Temporary() bool { return true }
53 54 // The following code is copied from the official implementation.
55 // https://github.com/golang/go/blob/4ce6a8e89668b87dce67e2f55802903d6eb9110a/src/os/error.go#L65-L104
56 57 func NewSyscallError(syscall string, err error) error {
58 if err == nil {
59 return nil
60 }
61 return &SyscallError{syscall, err}
62 }
63 64 // PathError records an error and the operation and file path that caused it.
65 type PathError = fs.PathError
66 67 // SyscallError records an error from a specific system call.
68 type SyscallError struct {
69 Syscall string
70 Err error
71 }
72 73 func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err.Error() }
74 75 func (e *SyscallError) Unwrap() error { return e.Err }
76 77 type timeout interface {
78 Timeout() bool
79 }
80 81 // Timeout reports whether this error represents a timeout.
82 func (e *SyscallError) Timeout() bool {
83 t, ok := e.Err.(timeout)
84 return ok && t.Timeout()
85 }
86 87 func IsExist(err error) bool {
88 return underlyingErrorIs(err, ErrExist)
89 }
90 91 func IsNotExist(err error) bool {
92 return underlyingErrorIs(err, ErrNotExist)
93 }
94 95 func IsPermission(err error) bool {
96 return underlyingErrorIs(err, ErrPermission)
97 }
98 99 func IsTimeout(err error) bool {
100 terr, ok := underlyingError(err).(timeout)
101 return ok && terr.Timeout()
102 }
103 104 func underlyingErrorIs(err, target error) bool {
105 // Note that this function is not errors.Is:
106 // underlyingError only unwraps the specific error-wrapping types
107 // that it historically did, not all errors implementing Unwrap().
108 err = underlyingError(err)
109 if err == target {
110 return true
111 }
112 // To preserve prior behavior, only examine syscall errors.
113 e, ok := err.(syscall.Errno)
114 return ok && e.Is(target)
115 }
116 117 // underlyingError returns the underlying error for known os error types.
118 func underlyingError(err error) error {
119 switch err := err.(type) {
120 case *PathError:
121 return err.Err
122 case *SyscallError:
123 return err.Err
124 }
125 return err
126 }
127