-
Notifications
You must be signed in to change notification settings - Fork 305
/
errors.go
496 lines (462 loc) · 13.4 KB
1
2
3
4
5
6
7
8
9
// Copyright 2016 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package errors defines the error handling used by all Upspin software.
package errors
import (
"bytes"
10
"encoding"
11
"encoding/binary"
12
13
"fmt"
"runtime"
14
"strings"
15
16
17
18
19
20
21
22
23
24
25
26
27
"upspin.io/log"
"upspin.io/upspin"
)
// Error is the type that implements the error interface.
// It contains a number of fields, each of different type.
// An Error value may leave some values unset.
type Error struct {
// Path is the Upspin path name of the item being accessed.
Path upspin.PathName
// User is the Upspin name of the user attempting the operation.
User upspin.UserName
28
29
// Op is the operation being performed, usually the name of the method
// being invoked (Get, Put, etc.). It should not contain an at sign @.
30
Op Op
31
32
33
34
35
// Kind is the class of error, such as permission failure,
// or "Other" if its class is unknown or irrelevant.
Kind Kind
// The underlying error that triggered this one, if any.
Err error
36
37
38
39
40
41
42
// Stack information; used only when the 'debug' build tag is set.
stack
}
func (e *Error) isZero() bool {
return e.Path == "" && e.User == "" && e.Op == "" && e.Kind == 0 && e.Err == nil
43
44
}
45
var (
46
47
48
_ error = (*Error)(nil)
_ encoding.BinaryUnmarshaler = (*Error)(nil)
_ encoding.BinaryMarshaler = (*Error)(nil)
49
)
50
51
52
53
54
// Op describes an operation, usually as the package and method,
// such as "key/server.Lookup".
type Op string
55
56
57
58
59
60
61
// Separator is the string used to separate nested errors. By
// default, to make errors easier on the eye, nested errors are
// indented on a new line. A server may instead choose to keep each
// error on a single line by modifying the separator string, perhaps
// to ":: ".
var Separator = ":\n\t"
62
63
64
65
// Kind defines the kind of error this is, mostly for use by systems
// such as FUSE that must act differently depending on the error.
type Kind uint8
66
// Kinds of errors.
67
68
69
70
71
//
// The values of the error kinds are common between both
// clients and servers. Do not reorder this list or remove
// any items since that will change their values.
// New items must be added only to the end.
72
const (
73
74
75
76
77
78
79
Other Kind = iota // Unclassified error. This value is not printed in the error message.
Invalid // Invalid operation for this type of item.
Permission // Permission denied.
IO // External I/O error such as network failure.
Exist // Item already exists.
NotExist // Item does not exist.
IsDir // Item is a directory.
80
NotDir // Item is not a directory.
81
82
83
84
NotEmpty // Directory not empty.
Private // Information withheld.
Internal // Internal error or inconsistency.
CannotDecrypt // No wrapped key for user with read access.
85
Transient // A transient error.
86
BrokenLink // Link target does not exist.
87
88
89
90
)
func (k Kind) String() string {
switch k {
91
92
case Other:
return "other error"
93
94
95
96
97
98
99
100
101
102
case Invalid:
return "invalid operation"
case Permission:
return "permission denied"
case IO:
return "I/O error"
case Exist:
return "item already exists"
case NotExist:
return "item does not exist"
103
104
case BrokenLink:
return "link target does not exist"
105
106
case IsDir:
return "item is a directory"
107
case NotDir:
108
return "item is not a directory"
109
110
case NotEmpty:
return "directory not empty"
111
112
case Private:
return "information withheld"
113
114
case Internal:
return "internal error"
115
116
case CannotDecrypt:
return `no wrapped key for user; owner must "upspin share -fix"`
117
118
case Transient:
return "transient error"
119
120
121
122
123
}
return "unknown error kind"
}
// E builds an error value from its arguments.
124
// There must be at least one argument or E panics.
125
126
127
128
129
130
131
132
133
// The type of each argument determines its meaning.
// If more than one argument of a given type is presented,
// only the last one is recorded.
//
// The types are:
// upspin.PathName
// The Upspin path name of the item being accessed.
// upspin.UserName
// The Upspin name of the user attempting the operation.
134
// errors.Op
135
// The operation being performed, usually the method
136
137
138
139
140
141
142
// being invoked (Get, Put, etc.).
// string
// Treated as an error message and assigned to the
// Err field after a call to errors.Str. To avoid a common
// class of misuse, if the string contains an @, it will be
// treated as a PathName or UserName, as appropriate. Use
// errors.Str explicitly to avoid this special-casing.
143
144
145
146
147
148
149
150
// errors.Kind
// The class of error, such as permission failure.
// error
// The underlying error that triggered this one.
//
// If the error is printed, only those items that have been
// set to non-zero values will appear in the result.
//
151
152
153
// If Kind is not specified or Other, we set it to the Kind of
// the underlying error.
//
154
155
func E(args ...interface{}) error {
if len(args) == 0 {
156
panic("call to errors.E with no arguments")
157
158
159
160
161
162
163
164
}
e := &Error{}
for _, arg := range args {
switch arg := arg.(type) {
case upspin.PathName:
e.Path = arg
case upspin.UserName:
e.User = arg
165
166
case Op:
e.Op = arg
167
case string:
168
169
170
171
// Someone might accidentally call us with a user or path name
// that is not of the right type. Take care of that and log it.
if strings.Contains(arg, "@") {
_, file, line, _ := runtime.Caller(1)
172
log.Printf("errors.E: unqualified type for %q from %s:%d", arg, file, line)
173
if strings.Contains(arg, "/") {
174
if e.Path == "" { // Don't overwrite a valid path.
175
176
e.Path = upspin.PathName(arg)
}
177
} else {
178
if e.User == "" { // Don't overwrite a valid user.
179
180
e.User = upspin.UserName(arg)
}
181
182
183
}
continue
}
184
e.Err = Str(arg)
185
186
case Kind:
e.Kind = arg
187
188
189
190
case *Error:
// Make a copy
copy := *arg
e.Err = ©
191
192
193
194
195
case error:
e.Err = arg
default:
_, file, line, _ := runtime.Caller(1)
log.Printf("errors.E: bad call from %s:%d: %v", file, line, args)
196
return Errorf("unknown type %T, value %v in error call", arg, arg)
197
198
}
}
199
200
201
202
// Populate stack information (only in debug mode).
e.populateStack()
203
204
prev, ok := e.Err.(*Error)
if !ok {
205
206
return e
}
207
208
// The previous error was also one of ours. Suppress duplications
209
210
211
212
213
214
215
216
217
218
219
220
221
// so the message won't contain the same kind, file name or user name
// twice.
if prev.Path == e.Path {
prev.Path = ""
}
if prev.User == e.User {
prev.User = ""
}
if prev.Kind == e.Kind {
prev.Kind = Other
}
// If this error has Kind unset or Other, pull up the inner one.
if e.Kind == Other {
222
e.Kind = prev.Kind
223
prev.Kind = Other
224
}
225
226
227
228
229
230
231
232
233
234
235
236
237
return e
}
// pad appends str to the buffer if the buffer already has some data.
func pad(b *bytes.Buffer, str string) {
if b.Len() == 0 {
return
}
b.WriteString(str)
}
func (e *Error) Error() string {
b := new(bytes.Buffer)
238
e.printStack(b)
239
240
241
242
if e.Op != "" {
pad(b, ": ")
b.WriteString(string(e.Op))
}
243
if e.Path != "" {
244
pad(b, ": ")
245
246
247
b.WriteString(string(e.Path))
}
if e.User != "" {
248
249
250
251
252
if e.Path == "" {
pad(b, ": ")
} else {
pad(b, ", ")
}
253
b.WriteString("user ")
254
255
256
257
258
259
260
b.WriteString(string(e.User))
}
if e.Kind != 0 {
pad(b, ": ")
b.WriteString(e.Kind.String())
}
if e.Err != nil {
261
262
// Indent on new line if we are cascading non-empty Upspin errors.
if prevErr, ok := e.Err.(*Error); ok {
263
if !prevErr.isZero() {
264
265
266
pad(b, Separator)
b.WriteString(e.Err.Error())
}
267
268
} else {
pad(b, ": ")
269
b.WriteString(e.Err.Error())
270
271
272
273
274
275
276
}
}
if b.Len() == 0 {
return "no error"
}
return b.String()
}
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
// Recreate the errors.New functionality of the standard Go errors package
// so we can create simple text errors when needed.
// Str returns an error that formats as the given text. It is intended to
// be used as the error-typed argument to the E function.
func Str(text string) error {
return &errorString{text}
}
// errorString is a trivial implementation of error.
type errorString struct {
s string
}
func (e *errorString) Error() string {
return e.s
}
296
// Errorf is equivalent to fmt.Errorf, but allows clients to import only this
297
298
299
300
301
// package for all error handling.
func Errorf(format string, args ...interface{}) error {
return &errorString{fmt.Sprintf(format, args...)}
}
302
303
304
// MarshalAppend marshals err into a byte slice. The result is appended to b,
// which may be nil.
// It returns the argument slice unchanged if the error is nil.
305
306
func (e *Error) MarshalAppend(b []byte) []byte {
if e == nil {
307
308
return b
}
309
310
b = appendString(b, string(e.Path))
b = appendString(b, string(e.User))
311
b = appendString(b, string(e.Op))
312
var tmp [16]byte // For use by PutVarint.
313
N := binary.PutVarint(tmp[:], int64(e.Kind))
314
b = append(b, tmp[:N]...)
315
b = MarshalErrorAppend(e.Err, b)
316
317
318
return b
}
319
// MarshalBinary marshals its receiver into a byte slice, which it returns.
320
// It returns nil if the error is nil. The returned error is always nil.
321
322
func (e *Error) MarshalBinary() ([]byte, error) {
return e.MarshalAppend(nil), nil
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
}
// MarshalErrorAppend marshals an arbitrary error into a byte slice.
// The result is appended to b, which may be nil.
// It returns the argument slice unchanged if the error is nil.
// If the error is not an *Error, it just records the result of err.Error().
// Otherwise it encodes the full Error struct.
func MarshalErrorAppend(err error, b []byte) []byte {
if err == nil {
return b
}
if e, ok := err.(*Error); ok {
// This is an errors.Error. Mark it as such.
b = append(b, 'E')
return e.MarshalAppend(b)
}
// Ordinary error.
b = append(b, 'e')
b = appendString(b, err.Error())
return b
}
// MarshalError marshals an arbitrary error and returns the byte slice.
// If the error is nil, it returns nil.
// It returns the argument slice unchanged if the error is nil.
// If the error is not an *Error, it just records the result of err.Error().
// Otherwise it encodes the full Error struct.
func MarshalError(err error) []byte {
return MarshalErrorAppend(err, nil)
}
355
356
// UnmarshalBinary unmarshals the byte slice into the receiver, which must be non-nil.
// The returned error is always nil.
357
func (e *Error) UnmarshalBinary(b []byte) error {
358
if len(b) == 0 {
359
return nil
360
361
362
}
data, b := getBytes(b)
if data != nil {
363
e.Path = upspin.PathName(data)
364
365
366
}
data, b = getBytes(b)
if data != nil {
367
e.User = upspin.UserName(data)
368
369
370
}
data, b = getBytes(b)
if data != nil {
371
e.Op = Op(data)
372
373
}
k, N := binary.Varint(b)
374
e.Kind = Kind(k)
375
b = b[N:]
376
e.Err = UnmarshalError(b)
377
return nil
378
379
380
}
// UnmarshalError unmarshals the byte slice into an error value.
381
382
// If the slice is nil or empty, it returns nil.
// Otherwise the byte slice must have been created by MarshalError or
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
// MarshalErrorAppend.
// If the encoded error was of type *Error, the returned error value
// will have that underlying type. Otherwise it will be just a simple
// value that implements the error interface.
func UnmarshalError(b []byte) error {
if len(b) == 0 {
return nil
}
code := b[0]
b = b[1:]
switch code {
case 'e':
// Plain error.
var data []byte
data, b = getBytes(b)
if len(b) != 0 {
log.Printf("Unmarshal error: trailing bytes")
}
return Str(string(data))
case 'E':
// Error value.
var err Error
405
err.UnmarshalBinary(b)
406
407
return &err
default:
408
log.Printf("Unmarshal error: corrupt data %q", b)
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
return Str(string(b))
}
}
func appendString(b []byte, str string) []byte {
var tmp [16]byte // For use by PutUvarint.
N := binary.PutUvarint(tmp[:], uint64(len(str)))
b = append(b, tmp[:N]...)
b = append(b, str...)
return b
}
// getBytes unmarshals the byte slice at b (uvarint count followed by bytes)
// and returns the slice followed by the remaining bytes.
// If there is insufficient data, both return values will be nil.
func getBytes(b []byte) (data, remaining []byte) {
u, N := binary.Uvarint(b)
if len(b) < N+int(u) {
log.Printf("Unmarshal error: bad encoding")
return nil, nil
}
if N == 0 {
log.Printf("Unmarshal error: bad encoding")
return nil, b
}
return b[N : N+int(u)], b[N+int(u):]
}
436
437
438
439
440
// Match compares its two error arguments. It can be used to check
// for expected errors in tests. Both arguments must have underlying
// type *Error or Match will return false. Otherwise it returns true
// iff every non-zero element of the first error is equal to the
441
442
443
444
445
446
// corresponding element of the second.
// If the Err field is a *Error, Match recurs on that field;
// otherwise it compares the strings returned by the Error methods.
// Elements that are in the second argument but not present in
// the first are ignored.
//
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
// For example,
// Match(errors.E(upspin.UserName("joe@schmoe.com"), errors.Permission), err)
// tests whether err is an Error with Kind=Permission and User=joe@schmoe.com.
func Match(err1, err2 error) bool {
e1, ok := err1.(*Error)
if !ok {
return false
}
e2, ok := err2.(*Error)
if !ok {
return false
}
if e1.Path != "" && e2.Path != e1.Path {
return false
}
if e1.User != "" && e2.User != e1.User {
return false
}
if e1.Op != "" && e2.Op != e1.Op {
return false
}
if e1.Kind != Other && e2.Kind != e1.Kind {
return false
}
471
if e1.Err != nil {
472
473
474
if _, ok := e1.Err.(*Error); ok {
return Match(e1.Err, e2.Err)
}
475
476
477
if e2.Err == nil || e2.Err.Error() != e1.Err.Error() {
return false
}
478
479
480
}
return true
}
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
// Is reports whether err is an *Error of the given Kind.
// If err is nil then Is returns false.
func Is(kind Kind, err error) bool {
e, ok := err.(*Error)
if !ok {
return false
}
if e.Kind != Other {
return e.Kind == kind
}
if e.Err != nil {
return Is(kind, e.Err)
}
return false
}