Skip to content

Latest commit

 

History

History
496 lines (462 loc) · 13.4 KB

errors.go

File metadata and controls

496 lines (462 loc) · 13.4 KB
 
Jun 15, 2016
Jun 15, 2016
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"
Jun 16, 2016
Jun 16, 2016
10
"encoding"
Jun 16, 2016
Jun 16, 2016
11
"encoding/binary"
Jun 15, 2016
Jun 15, 2016
12
13
"fmt"
"runtime"
Jun 15, 2016
Jun 15, 2016
14
"strings"
Jun 15, 2016
Jun 15, 2016
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
Jun 16, 2016
Jun 16, 2016
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 @.
Nov 30, 2017
Nov 30, 2017
30
Op Op
Jun 15, 2016
Jun 15, 2016
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
Aug 25, 2016
Aug 25, 2016
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
Jun 15, 2016
Jun 15, 2016
43
44
}
Jun 16, 2016
Jun 16, 2016
45
var (
Aug 25, 2016
Aug 25, 2016
46
47
48
_ error = (*Error)(nil)
_ encoding.BinaryUnmarshaler = (*Error)(nil)
_ encoding.BinaryMarshaler = (*Error)(nil)
Jun 16, 2016
Jun 16, 2016
49
)
Jun 15, 2016
Jun 15, 2016
50
Nov 30, 2017
Nov 30, 2017
51
52
53
54
// Op describes an operation, usually as the package and method,
// such as "key/server.Lookup".
type Op string
Jun 22, 2016
Jun 22, 2016
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"
Jun 15, 2016
Jun 15, 2016
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
Jun 28, 2016
Jun 28, 2016
66
// Kinds of errors.
Mar 25, 2017
Mar 25, 2017
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.
Jun 15, 2016
Jun 15, 2016
72
const (
Dec 5, 2016
Dec 5, 2016
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.
Nov 13, 2017
Nov 13, 2017
80
NotDir // Item is not a directory.
Dec 5, 2016
Dec 5, 2016
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.
Jan 30, 2017
Jan 30, 2017
85
Transient // A transient error.
Mar 25, 2017
Mar 25, 2017
86
BrokenLink // Link target does not exist.
Jun 15, 2016
Jun 15, 2016
87
88
89
90
)
func (k Kind) String() string {
switch k {
Jun 22, 2016
Jun 22, 2016
91
92
case Other:
return "other error"
Jun 15, 2016
Jun 15, 2016
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"
Mar 20, 2017
Mar 20, 2017
103
104
case BrokenLink:
return "link target does not exist"
Jun 22, 2016
Jun 22, 2016
105
106
case IsDir:
return "item is a directory"
Jun 20, 2016
Jun 20, 2016
107
case NotDir:
Jun 22, 2016
Jun 22, 2016
108
return "item is not a directory"
Jun 20, 2016
Jun 20, 2016
109
110
case NotEmpty:
return "directory not empty"
Nov 1, 2016
Nov 1, 2016
111
112
case Private:
return "information withheld"
Aug 10, 2016
Aug 10, 2016
113
114
case Internal:
return "internal error"
Dec 5, 2016
Dec 5, 2016
115
116
case CannotDecrypt:
return `no wrapped key for user; owner must "upspin share -fix"`
Jan 30, 2017
Jan 30, 2017
117
118
case Transient:
return "transient error"
Jun 15, 2016
Jun 15, 2016
119
120
121
122
123
}
return "unknown error kind"
}
// E builds an error value from its arguments.
Aug 8, 2016
Aug 8, 2016
124
// There must be at least one argument or E panics.
Jun 15, 2016
Jun 15, 2016
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.
Nov 30, 2017
Nov 30, 2017
134
// errors.Op
Jun 15, 2016
Jun 15, 2016
135
// The operation being performed, usually the method
Nov 30, 2017
Nov 30, 2017
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.
Jun 15, 2016
Jun 15, 2016
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.
//
Jun 20, 2016
Jun 20, 2016
151
152
153
// If Kind is not specified or Other, we set it to the Kind of
// the underlying error.
//
Jun 15, 2016
Jun 15, 2016
154
155
func E(args ...interface{}) error {
if len(args) == 0 {
Aug 8, 2016
Aug 8, 2016
156
panic("call to errors.E with no arguments")
Jun 15, 2016
Jun 15, 2016
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
Nov 30, 2017
Nov 30, 2017
165
166
case Op:
e.Op = arg
Jun 15, 2016
Jun 15, 2016
167
case string:
Jun 15, 2016
Jun 15, 2016
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)
Jun 15, 2016
Jun 15, 2016
172
log.Printf("errors.E: unqualified type for %q from %s:%d", arg, file, line)
Jun 15, 2016
Jun 15, 2016
173
if strings.Contains(arg, "/") {
Jul 18, 2017
Jul 18, 2017
174
if e.Path == "" { // Don't overwrite a valid path.
Jun 16, 2016
Jun 16, 2016
175
176
e.Path = upspin.PathName(arg)
}
Jun 15, 2016
Jun 15, 2016
177
} else {
Jul 18, 2017
Jul 18, 2017
178
if e.User == "" { // Don't overwrite a valid user.
Jun 16, 2016
Jun 16, 2016
179
180
e.User = upspin.UserName(arg)
}
Jun 15, 2016
Jun 15, 2016
181
182
183
}
continue
}
Nov 30, 2017
Nov 30, 2017
184
e.Err = Str(arg)
Jun 15, 2016
Jun 15, 2016
185
186
case Kind:
e.Kind = arg
Jun 28, 2016
Jun 28, 2016
187
188
189
190
case *Error:
// Make a copy
copy := *arg
e.Err = &copy
Jun 15, 2016
Jun 15, 2016
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)
Jun 18, 2016
Jun 18, 2016
196
return Errorf("unknown type %T, value %v in error call", arg, arg)
Jun 15, 2016
Jun 15, 2016
197
198
}
}
Aug 25, 2016
Aug 25, 2016
199
200
201
202
// Populate stack information (only in debug mode).
e.populateStack()
Jun 20, 2016
Jun 20, 2016
203
204
prev, ok := e.Err.(*Error)
if !ok {
Jun 20, 2016
Jun 20, 2016
205
206
return e
}
Jun 28, 2016
Jun 28, 2016
207
208
// The previous error was also one of ours. Suppress duplications
Jun 20, 2016
Jun 20, 2016
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 {
Jun 20, 2016
Jun 20, 2016
222
e.Kind = prev.Kind
Jun 20, 2016
Jun 20, 2016
223
prev.Kind = Other
Jun 20, 2016
Jun 20, 2016
224
}
Jun 15, 2016
Jun 15, 2016
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)
Aug 25, 2016
Aug 25, 2016
238
e.printStack(b)
Dec 5, 2017
Dec 5, 2017
239
240
241
242
if e.Op != "" {
pad(b, ": ")
b.WriteString(string(e.Op))
}
Jun 15, 2016
Jun 15, 2016
243
if e.Path != "" {
Aug 25, 2016
Aug 25, 2016
244
pad(b, ": ")
Jun 15, 2016
Jun 15, 2016
245
246
247
b.WriteString(string(e.Path))
}
if e.User != "" {
Aug 25, 2016
Aug 25, 2016
248
249
250
251
252
if e.Path == "" {
pad(b, ": ")
} else {
pad(b, ", ")
}
Jun 18, 2016
Jun 18, 2016
253
b.WriteString("user ")
Jun 15, 2016
Jun 15, 2016
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 {
Jun 28, 2016
Jun 28, 2016
261
262
// Indent on new line if we are cascading non-empty Upspin errors.
if prevErr, ok := e.Err.(*Error); ok {
Aug 25, 2016
Aug 25, 2016
263
if !prevErr.isZero() {
Jun 28, 2016
Jun 28, 2016
264
265
266
pad(b, Separator)
b.WriteString(e.Err.Error())
}
Jun 15, 2016
Jun 15, 2016
267
268
} else {
pad(b, ": ")
Jun 28, 2016
Jun 28, 2016
269
b.WriteString(e.Err.Error())
Jun 15, 2016
Jun 15, 2016
270
271
272
273
274
275
276
}
}
if b.Len() == 0 {
return "no error"
}
return b.String()
}
Jun 16, 2016
Jun 16, 2016
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
}
Dec 8, 2017
Dec 8, 2017
296
// Errorf is equivalent to fmt.Errorf, but allows clients to import only this
Jun 18, 2016
Jun 18, 2016
297
298
299
300
301
// package for all error handling.
func Errorf(format string, args ...interface{}) error {
return &errorString{fmt.Sprintf(format, args...)}
}
Jun 16, 2016
Jun 16, 2016
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.
Jun 28, 2016
Jun 28, 2016
305
306
func (e *Error) MarshalAppend(b []byte) []byte {
if e == nil {
Jun 16, 2016
Jun 16, 2016
307
308
return b
}
Jun 28, 2016
Jun 28, 2016
309
310
b = appendString(b, string(e.Path))
b = appendString(b, string(e.User))
Nov 30, 2017
Nov 30, 2017
311
b = appendString(b, string(e.Op))
Jun 16, 2016
Jun 16, 2016
312
var tmp [16]byte // For use by PutVarint.
Jun 28, 2016
Jun 28, 2016
313
N := binary.PutVarint(tmp[:], int64(e.Kind))
Jun 16, 2016
Jun 16, 2016
314
b = append(b, tmp[:N]...)
Jun 28, 2016
Jun 28, 2016
315
b = MarshalErrorAppend(e.Err, b)
Jun 16, 2016
Jun 16, 2016
316
317
318
return b
}
Jun 28, 2016
Jun 28, 2016
319
// MarshalBinary marshals its receiver into a byte slice, which it returns.
Jun 16, 2016
Jun 16, 2016
320
// It returns nil if the error is nil. The returned error is always nil.
Jun 28, 2016
Jun 28, 2016
321
322
func (e *Error) MarshalBinary() ([]byte, error) {
return e.MarshalAppend(nil), nil
Jun 16, 2016
Jun 16, 2016
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)
}
Jun 16, 2016
Jun 16, 2016
355
356
// UnmarshalBinary unmarshals the byte slice into the receiver, which must be non-nil.
// The returned error is always nil.
Jun 28, 2016
Jun 28, 2016
357
func (e *Error) UnmarshalBinary(b []byte) error {
Jun 16, 2016
Jun 16, 2016
358
if len(b) == 0 {
Jun 16, 2016
Jun 16, 2016
359
return nil
Jun 16, 2016
Jun 16, 2016
360
361
362
}
data, b := getBytes(b)
if data != nil {
Jun 28, 2016
Jun 28, 2016
363
e.Path = upspin.PathName(data)
Jun 16, 2016
Jun 16, 2016
364
365
366
}
data, b = getBytes(b)
if data != nil {
Jun 28, 2016
Jun 28, 2016
367
e.User = upspin.UserName(data)
Jun 16, 2016
Jun 16, 2016
368
369
370
}
data, b = getBytes(b)
if data != nil {
Nov 30, 2017
Nov 30, 2017
371
e.Op = Op(data)
Jun 16, 2016
Jun 16, 2016
372
373
}
k, N := binary.Varint(b)
Jun 28, 2016
Jun 28, 2016
374
e.Kind = Kind(k)
Jun 16, 2016
Jun 16, 2016
375
b = b[N:]
Jun 28, 2016
Jun 28, 2016
376
e.Err = UnmarshalError(b)
Jun 16, 2016
Jun 16, 2016
377
return nil
Jun 16, 2016
Jun 16, 2016
378
379
380
}
// UnmarshalError unmarshals the byte slice into an error value.
Aug 11, 2016
Aug 11, 2016
381
382
// If the slice is nil or empty, it returns nil.
// Otherwise the byte slice must have been created by MarshalError or
Jun 16, 2016
Jun 16, 2016
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
Jun 16, 2016
Jun 16, 2016
405
err.UnmarshalBinary(b)
Jun 16, 2016
Jun 16, 2016
406
407
return &err
default:
Jul 10, 2017
Jul 10, 2017
408
log.Printf("Unmarshal error: corrupt data %q", b)
Jun 16, 2016
Jun 16, 2016
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):]
}
Aug 8, 2016
Aug 8, 2016
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
Aug 31, 2016
Aug 31, 2016
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.
//
Aug 8, 2016
Aug 8, 2016
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
}
Aug 8, 2016
Aug 8, 2016
471
if e1.Err != nil {
Aug 31, 2016
Aug 31, 2016
472
473
474
if _, ok := e1.Err.(*Error); ok {
return Match(e1.Err, e2.Err)
}
Aug 8, 2016
Aug 8, 2016
475
476
477
if e2.Err == nil || e2.Err.Error() != e1.Err.Error() {
return false
}
Aug 8, 2016
Aug 8, 2016
478
479
480
}
return true
}
Oct 25, 2017
Oct 25, 2017
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
}