github.com/mckael/restic@v0.8.3/internal/restic/id.go (about) 1 package restic 2 3 import ( 4 "crypto/rand" 5 "crypto/sha256" 6 "encoding/hex" 7 "encoding/json" 8 "io" 9 10 "github.com/restic/restic/internal/errors" 11 ) 12 13 // Hash returns the ID for data. 14 func Hash(data []byte) ID { 15 return sha256.Sum256(data) 16 } 17 18 // idSize contains the size of an ID, in bytes. 19 const idSize = sha256.Size 20 21 // ID references content within a repository. 22 type ID [idSize]byte 23 24 // ParseID converts the given string to an ID. 25 func ParseID(s string) (ID, error) { 26 b, err := hex.DecodeString(s) 27 28 if err != nil { 29 return ID{}, errors.Wrap(err, "hex.DecodeString") 30 } 31 32 if len(b) != idSize { 33 return ID{}, errors.New("invalid length for hash") 34 } 35 36 id := ID{} 37 copy(id[:], b) 38 39 return id, nil 40 } 41 42 func (id ID) String() string { 43 return hex.EncodeToString(id[:]) 44 } 45 46 // NewRandomID returns a randomly generated ID. When reading from rand fails, 47 // the function panics. 48 func NewRandomID() ID { 49 id := ID{} 50 _, err := io.ReadFull(rand.Reader, id[:]) 51 if err != nil { 52 panic(err) 53 } 54 return id 55 } 56 57 const shortStr = 4 58 59 // Str returns the shortened string version of id. 60 func (id *ID) Str() string { 61 if id == nil { 62 return "[nil]" 63 } 64 65 if id.IsNull() { 66 return "[null]" 67 } 68 69 return hex.EncodeToString(id[:shortStr]) 70 } 71 72 // IsNull returns true iff id only consists of null bytes. 73 func (id ID) IsNull() bool { 74 var nullID ID 75 76 return id == nullID 77 } 78 79 // Equal compares an ID to another other. 80 func (id ID) Equal(other ID) bool { 81 return id == other 82 } 83 84 // EqualString compares this ID to another one, given as a string. 85 func (id ID) EqualString(other string) (bool, error) { 86 s, err := hex.DecodeString(other) 87 if err != nil { 88 return false, errors.Wrap(err, "hex.DecodeString") 89 } 90 91 id2 := ID{} 92 copy(id2[:], s) 93 94 return id == id2, nil 95 } 96 97 // MarshalJSON returns the JSON encoding of id. 98 func (id ID) MarshalJSON() ([]byte, error) { 99 return json.Marshal(id.String()) 100 } 101 102 // UnmarshalJSON parses the JSON-encoded data and stores the result in id. 103 func (id *ID) UnmarshalJSON(b []byte) error { 104 var s string 105 err := json.Unmarshal(b, &s) 106 if err != nil { 107 return errors.Wrap(err, "Unmarshal") 108 } 109 110 _, err = hex.Decode(id[:], []byte(s)) 111 if err != nil { 112 return errors.Wrap(err, "hex.Decode") 113 } 114 115 return nil 116 } 117 118 // IDFromHash returns the ID for the hash. 119 func IDFromHash(hash []byte) (id ID) { 120 if len(hash) != idSize { 121 panic("invalid hash type, not enough/too many bytes") 122 } 123 124 copy(id[:], hash) 125 return id 126 }