2014-09-23 20:39:12 +00:00
|
|
|
package backend
|
|
|
|
|
|
|
|
import (
|
|
|
|
"crypto/sha256"
|
2014-11-24 20:12:32 +00:00
|
|
|
"errors"
|
2014-09-23 20:39:12 +00:00
|
|
|
)
|
|
|
|
|
2014-11-24 21:09:22 +00:00
|
|
|
const (
|
2015-03-28 10:50:23 +00:00
|
|
|
MinPrefixLength = 8
|
2014-11-24 21:09:22 +00:00
|
|
|
)
|
|
|
|
|
2014-11-24 20:12:32 +00:00
|
|
|
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)
|
2015-03-22 15:38:03 +00:00
|
|
|
id := make([]byte, IDSize)
|
2014-09-23 20:39:12 +00:00
|
|
|
copy(id, h[:])
|
|
|
|
return id
|
|
|
|
}
|
2014-11-24 20:12:32 +00:00
|
|
|
|
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)
|
2014-11-24 20:12:32 +00:00
|
|
|
|
2015-03-28 10:50:23 +00:00
|
|
|
match := ""
|
2014-11-24 20:12:32 +00:00
|
|
|
|
|
|
|
// 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
|
2014-11-24 20:12:32 +00:00
|
|
|
} else {
|
2015-03-28 10:50:23 +00:00
|
|
|
return "", ErrMultipleIDMatches
|
2014-11-24 20:12:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-28 10:50:23 +00:00
|
|
|
if match != "" {
|
2014-11-24 20:12:32 +00:00
|
|
|
return match, nil
|
|
|
|
}
|
|
|
|
|
2015-03-28 10:50:23 +00:00
|
|
|
return "", ErrNoIDPrefixFound
|
2014-11-24 20:12:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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) {
|
2014-11-24 20:12:32 +00:00
|
|
|
// find snapshot id with prefix
|
2015-03-28 10:50:23 +00:00
|
|
|
name, err := Find(be, Snapshot, s)
|
2014-11-24 20:12:32 +00:00
|
|
|
if err != nil {
|
2015-03-28 10:50:23 +00:00
|
|
|
return "", err
|
2014-11-24 20:12:32 +00:00
|
|
|
}
|
|
|
|
|
2015-03-28 10:50:23 +00:00
|
|
|
return name, nil
|
2014-11-24 20:12:32 +00:00
|
|
|
}
|
2014-11-24 21:09:22 +00:00
|
|
|
|
|
|
|
// 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)
|
|
|
|
|
2014-11-24 21:09:22 +00:00
|
|
|
// 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)
|
2014-11-24 21:09:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
2014-11-24 21:09:22 +00:00
|
|
|
|
2015-03-28 10:50:23 +00:00
|
|
|
for _, name := range list {
|
|
|
|
if last == name[:l] {
|
2014-11-24 21:09:22 +00:00
|
|
|
continue outer
|
|
|
|
}
|
2015-03-28 10:50:23 +00:00
|
|
|
last = name[:l]
|
2014-11-24 21:09:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return l, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return IDSize, nil
|
|
|
|
}
|