restic/backend/generic.go

99 lines
2 KiB
Go
Raw Normal View History

2014-09-23 20:39:12 +00:00
package backend
import (
"crypto/sha256"
"errors"
2014-09-23 20:39:12 +00:00
)
const (
2015-03-28 10:50:23 +00:00
MinPrefixLength = 8
)
var (
ErrNoIDPrefixFound = errors.New("no ID found")
ErrMultipleIDMatches = errors.New("multiple IDs with prefix found")
)
2015-02-11 18:25:43 +00:00
var (
hashData = sha256.Sum256
)
const hashSize = sha256.Size
2014-09-23 20:39:12 +00:00
// Hash returns the ID for data.
func Hash(data []byte) ID {
2015-02-11 18:25:43 +00:00
h := hashData(data)
id := idPool.Get().(ID)
2014-09-23 20:39:12 +00:00
copy(id, h[:])
return id
}
2015-03-28 10:50:23 +00:00
// Find loads the list of all blobs of type t and searches for names which
// start with prefix. If none is found, nil and ErrNoIDPrefixFound is returned.
// If more than one is found, nil and ErrMultipleIDMatches is returned.
func Find(be Lister, t Type, prefix string) (string, error) {
done := make(chan struct{})
defer close(done)
2015-03-28 10:50:23 +00:00
match := ""
// TODO: optimize by sorting list etc.
2015-03-28 10:50:23 +00:00
for name := range be.List(t, done) {
if prefix == name[:len(prefix)] {
if match == "" {
match = name
} else {
2015-03-28 10:50:23 +00:00
return "", ErrMultipleIDMatches
}
}
}
2015-03-28 10:50:23 +00:00
if match != "" {
return match, nil
}
2015-03-28 10:50:23 +00:00
return "", ErrNoIDPrefixFound
}
// FindSnapshot takes a string and tries to find a snapshot whose ID matches
// the string as closely as possible.
2015-03-28 10:50:23 +00:00
func FindSnapshot(be Lister, s string) (string, error) {
// find snapshot id with prefix
2015-03-28 10:50:23 +00:00
name, err := Find(be, Snapshot, s)
if err != nil {
2015-03-28 10:50:23 +00:00
return "", err
}
2015-03-28 10:50:23 +00:00
return name, nil
}
// PrefixLength returns the number of bytes required so that all prefixes of
2015-03-28 10:50:23 +00:00
// all names of type t are unique.
2014-12-21 16:02:49 +00:00
func PrefixLength(be Lister, t Type) (int, error) {
2015-03-28 10:50:23 +00:00
done := make(chan struct{})
defer close(done)
// load all IDs of the given type
2015-03-28 10:50:23 +00:00
list := make([]string, 0, 100)
for name := range be.List(t, done) {
list = append(list, name)
}
// select prefixes of length l, test if the last one is the same as the current one
outer:
for l := MinPrefixLength; l < IDSize; l++ {
2015-03-28 10:50:23 +00:00
var last string
2015-03-28 10:50:23 +00:00
for _, name := range list {
if last == name[:l] {
continue outer
}
2015-03-28 10:50:23 +00:00
last = name[:l]
}
return l, nil
}
return IDSize, nil
}