This repository has been archived by the owner on Apr 27, 2024. It is now read-only.
forked from pterodactyl/wings
/
errors.go
139 lines (123 loc) · 4.39 KB
/
errors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package filesystem
import (
"fmt"
"emperror.dev/errors"
"github.com/apex/log"
)
type ErrorCode string
const (
ErrCodeIsDirectory ErrorCode = "E_ISDIR"
ErrCodeDiskSpace ErrorCode = "E_NODISK"
ErrCodeUnknownArchive ErrorCode = "E_UNKNFMT"
ErrCodePathResolution ErrorCode = "E_BADPATH"
ErrCodeDenylistFile ErrorCode = "E_DENYLIST"
ErrCodeUnknownError ErrorCode = "E_UNKNOWN"
ErrNotExist ErrorCode = "E_NOTEXIST"
)
type Error struct {
code ErrorCode
// Contains the underlying error leading to this. This value may or may not be
// present, it is entirely dependent on how this error was triggered.
err error
// This contains the value of the final destination that triggered this specific
// error event.
resolved string
// This value is generally only present on errors stemming from a path resolution
// error. For everything else you should be setting and reading the resolved path
// value which will be far more useful.
path string
}
// newFilesystemError returns a new error instance with a stack trace associated.
func newFilesystemError(code ErrorCode, err error) error {
if err != nil {
return errors.WithStackDepth(&Error{code: code, err: err}, 1)
}
return errors.WithStackDepth(&Error{code: code}, 1)
}
// Code returns the ErrorCode for this specific error instance.
func (e *Error) Code() ErrorCode {
return e.code
}
// Returns a human-readable error string to identify the Error by.
func (e *Error) Error() string {
switch e.code {
case ErrCodeIsDirectory:
return fmt.Sprintf("filesystem: cannot perform action: [%s] is a directory", e.resolved)
case ErrCodeDiskSpace:
return "filesystem: not enough disk space"
case ErrCodeUnknownArchive:
return "filesystem: unknown archive format"
case ErrCodeDenylistFile:
r := e.resolved
if r == "" {
r = "<empty>"
}
return fmt.Sprintf("filesystem: file access prohibited: [%s] is on the denylist", r)
case ErrCodePathResolution:
r := e.resolved
if r == "" {
r = "<empty>"
}
return fmt.Sprintf("filesystem: server path [%s] resolves to a location outside the server root: %s", e.path, r)
case ErrNotExist:
return "filesystem: does not exist"
case ErrCodeUnknownError:
fallthrough
default:
return fmt.Sprintf("filesystem: an error occurred: %s", e.Unwrap())
}
}
// Unwrap returns the underlying cause of this filesystem error. In some causes
// there may not be a cause present, in which case nil will be returned.
func (e *Error) Unwrap() error {
return e.err
}
// Generates an error logger instance with some basic information.
func (fs *Filesystem) error(err error) *log.Entry {
return log.WithField("subsystem", "filesystem").WithField("root", fs.root).WithField("error", err)
}
// Handle errors encountered when walking through directories.
//
// If there is a path resolution error just skip the item entirely. Only return this for a
// directory, otherwise return nil. Returning this error for a file will stop the walking
// for the remainder of the directory. This is assuming an os.FileInfo struct was even returned.
// func (fs *Filesystem) handleWalkerError(err error, f os.FileInfo) error {
// if !IsErrorCode(err, ErrCodePathResolution) {
// return err
// }
// if f != nil && f.IsDir() {
// return filepath.SkipDir
// }
// return nil
// }
// IsFilesystemError checks if the given error is one of the Filesystem errors.
func IsFilesystemError(err error) bool {
var fserr *Error
if err != nil && errors.As(err, &fserr) {
return true
}
return false
}
// IsErrorCode checks if "err" is a filesystem Error type. If so, it will then
// drop in and check that the error code is the same as the provided ErrorCode
// passed in "code".
func IsErrorCode(err error, code ErrorCode) bool {
var fserr *Error
if err != nil && errors.As(err, &fserr) {
return fserr.code == code
}
return false
}
// NewBadPathResolution returns a new BadPathResolution error.
func NewBadPathResolution(path string, resolved string) error {
return errors.WithStackDepth(&Error{code: ErrCodePathResolution, path: path, resolved: resolved}, 1)
}
// wrapError wraps the provided error as a Filesystem error and attaches the
// provided resolved source to it. If the error is already a Filesystem error
// no action is taken.
func wrapError(err error, resolved string) error {
if err == nil || IsFilesystemError(err) {
return err
}
return errors.WithStackDepth(&Error{code: ErrCodeUnknownError, err: err, resolved: resolved}, 1)
}