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  }