diff --git a/internal/archiver/testing_test.go b/internal/archiver/testing_test.go index e11b86250..6f6904e3f 100644 --- a/internal/archiver/testing_test.go +++ b/internal/archiver/testing_test.go @@ -217,7 +217,7 @@ func TestTestWalkFiles(t *testing.T) { return err } - got[p] = fmt.Sprintf("%v", item) + got[p] = fmt.Sprint(item) return nil }) diff --git a/internal/cache/file.go b/internal/cache/file.go index 490b2b311..8dafdfc56 100644 --- a/internal/cache/file.go +++ b/internal/cache/file.go @@ -59,13 +59,14 @@ func (c *Cache) load(h restic.Handle, length int, offset int64) (io.ReadCloser, return nil, errors.WithStack(err) } - if fi.Size() <= int64(crypto.CiphertextLength(0)) { + size := fi.Size() + if size <= int64(crypto.CiphertextLength(0)) { _ = f.Close() _ = c.remove(h) return nil, errors.Errorf("cached file %v is truncated, removing", h) } - if fi.Size() < offset+int64(length) { + if size < offset+int64(length) { _ = f.Close() _ = c.remove(h) return nil, errors.Errorf("cached file %v is too small, removing", h) diff --git a/internal/cache/file_test.go b/internal/cache/file_test.go index 3e92c1d96..17fc5048f 100644 --- a/internal/cache/file_test.go +++ b/internal/cache/file_test.go @@ -97,7 +97,7 @@ func TestFiles(t *testing.T) { } for _, tpe := range tests { - t.Run(fmt.Sprintf("%v", tpe), func(t *testing.T) { + t.Run(tpe.String(), func(t *testing.T) { ids := generateRandomFiles(t, tpe, c) id := randomID(ids) diff --git a/internal/restic/blob.go b/internal/restic/blob.go index 4ac149adb..260f40fde 100644 --- a/internal/restic/blob.go +++ b/internal/restic/blob.go @@ -114,11 +114,7 @@ func (h BlobHandles) Less(i, j int) bool { continue } - if b < h[j].ID[k] { - return true - } - - return false + return b < h[j].ID[k] } return h[i].Type < h[j].Type @@ -133,5 +129,5 @@ func (h BlobHandles) String() string { for _, e := range h { elements = append(elements, e.String()) } - return fmt.Sprintf("%v", elements) + return fmt.Sprint(elements) } diff --git a/internal/restic/file.go b/internal/restic/file.go index d058a71c0..0e9f046ae 100644 --- a/internal/restic/file.go +++ b/internal/restic/file.go @@ -7,18 +7,38 @@ import ( ) // FileType is the type of a file in the backend. -type FileType string +type FileType uint8 // These are the different data types a backend can store. const ( - PackFile FileType = "data" // use data, as packs are stored under /data in repo - KeyFile FileType = "key" - LockFile FileType = "lock" - SnapshotFile FileType = "snapshot" - IndexFile FileType = "index" - ConfigFile FileType = "config" + PackFile FileType = 1 + iota + KeyFile + LockFile + SnapshotFile + IndexFile + ConfigFile ) +func (t FileType) String() string { + s := "invalid" + switch t { + case PackFile: + // Spelled "data" instead of "pack" for historical reasons. + s = "data" + case KeyFile: + s = "key" + case LockFile: + s = "lock" + case SnapshotFile: + s = "snapshot" + case IndexFile: + s = "index" + case ConfigFile: + s = "config" + } + return s +} + // Handle is used to store and access data in a backend. type Handle struct { Type FileType @@ -36,10 +56,6 @@ func (h Handle) String() string { // Valid returns an error if h is not valid. func (h Handle) Valid() error { - if h.Type == "" { - return errors.New("type is empty") - } - switch h.Type { case PackFile: case KeyFile: @@ -48,7 +64,7 @@ func (h Handle) Valid() error { case IndexFile: case ConfigFile: default: - return errors.Errorf("invalid Type %q", h.Type) + return errors.Errorf("invalid Type %d", h.Type) } if h.Type == ConfigFile { diff --git a/internal/restic/file_test.go b/internal/restic/file_test.go index 76f00baac..cc54c2924 100644 --- a/internal/restic/file_test.go +++ b/internal/restic/file_test.go @@ -1,20 +1,28 @@ package restic -import "testing" +import ( + "testing" -var handleTests = []struct { - h Handle - valid bool -}{ - {Handle{Name: "foo"}, false}, - {Handle{Type: "foobar"}, false}, - {Handle{Type: ConfigFile, Name: ""}, true}, - {Handle{Type: PackFile, Name: ""}, false}, - {Handle{Type: "", Name: "x"}, false}, - {Handle{Type: LockFile, Name: "010203040506"}, true}, + rtest "github.com/restic/restic/internal/test" +) + +func TestHandleString(t *testing.T) { + rtest.Equals(t, "", Handle{Type: PackFile, Name: "foobar"}.String()) + rtest.Equals(t, "", Handle{Type: LockFile, Name: "1"}.String()) } func TestHandleValid(t *testing.T) { + var handleTests = []struct { + h Handle + valid bool + }{ + {Handle{Name: "foo"}, false}, + {Handle{Type: 0}, false}, + {Handle{Type: ConfigFile, Name: ""}, true}, + {Handle{Type: PackFile, Name: ""}, false}, + {Handle{Type: LockFile, Name: "010203040506"}, true}, + } + for i, test := range handleTests { err := test.h.Valid() if err != nil && test.valid { diff --git a/internal/restic/id.go b/internal/restic/id.go index 5a25e0ebe..e71c6d71b 100644 --- a/internal/restic/id.go +++ b/internal/restic/id.go @@ -6,8 +6,6 @@ import ( "fmt" "io" - "github.com/restic/restic/internal/errors" - "github.com/minio/sha256-simd" ) @@ -24,14 +22,13 @@ type ID [idSize]byte // ParseID converts the given string to an ID. func ParseID(s string) (ID, error) { - b, err := hex.DecodeString(s) - - if err != nil { - return ID{}, errors.Wrap(err, "hex.DecodeString") + if len(s) != hex.EncodedLen(idSize) { + return ID{}, fmt.Errorf("invalid length for ID: %q", s) } - if len(b) != idSize { - return ID{}, errors.New("invalid length for hash") + b, err := hex.DecodeString(s) + if err != nil { + return ID{}, fmt.Errorf("invalid ID: %s", err) } id := ID{} @@ -96,34 +93,21 @@ func (id ID) MarshalJSON() ([]byte, error) { // UnmarshalJSON parses the JSON-encoded data and stores the result in id. func (id *ID) UnmarshalJSON(b []byte) error { // check string length - if len(b) < 2 { - return fmt.Errorf("invalid ID: %q", b) + if len(b) != len(`""`)+hex.EncodedLen(idSize) { + return fmt.Errorf("invalid length for ID: %q", b) } - if len(b)%2 != 0 { - return fmt.Errorf("invalid ID length: %q", b) - } - - // check string delimiters - if b[0] != '"' && b[0] != '\'' { + if b[0] != '"' { return fmt.Errorf("invalid start of string: %q", b[0]) } - last := len(b) - 1 - if b[0] != b[last] { - return fmt.Errorf("starting string delimiter (%q) does not match end (%q)", b[0], b[last]) - } - - // strip JSON string delimiters - b = b[1:last] - - if len(b) != 2*len(id) { - return fmt.Errorf("invalid length for ID") - } + // Strip JSON string delimiters. The json.Unmarshaler contract says we get + // a valid JSON value, so we don't need to check that b[len(b)-1] == '"'. + b = b[1 : len(b)-1] _, err := hex.Decode(id[:], b) if err != nil { - return errors.Wrap(err, "hex.Decode") + return fmt.Errorf("invalid ID: %s", err) } return nil diff --git a/internal/restic/ids.go b/internal/restic/ids.go index cc5ad18da..b3e6b6f22 100644 --- a/internal/restic/ids.go +++ b/internal/restic/ids.go @@ -65,5 +65,5 @@ func (ids IDs) String() string { for _, id := range ids { elements = append(elements, shortID(id)) } - return fmt.Sprintf("%v", elements) + return fmt.Sprint(elements) } diff --git a/internal/restic/tag_list.go b/internal/restic/tag_list.go index 4d57cb14b..b293b14f7 100644 --- a/internal/restic/tag_list.go +++ b/internal/restic/tag_list.go @@ -37,7 +37,7 @@ func (TagList) Type() string { type TagLists []TagList func (l TagLists) String() string { - return fmt.Sprintf("%v", []TagList(l)) + return fmt.Sprint([]TagList(l)) } // Flatten returns the list of all tags provided in TagLists