2016-08-31 22:39:36 +02:00
|
|
|
package restic
|
|
|
|
|
2017-06-03 17:39:57 +02:00
|
|
|
import (
|
|
|
|
"context"
|
2020-11-10 22:43:18 +01:00
|
|
|
"fmt"
|
2017-06-03 17:39:57 +02:00
|
|
|
)
|
2016-08-31 22:39:36 +02:00
|
|
|
|
2020-11-10 22:43:18 +01:00
|
|
|
// A MultipleIDMatchesError is returned by Find() when multiple IDs with a
|
|
|
|
// given prefix are found.
|
|
|
|
type MultipleIDMatchesError struct{ prefix string }
|
|
|
|
|
|
|
|
func (e *MultipleIDMatchesError) Error() string {
|
|
|
|
return fmt.Sprintf("multiple IDs with prefix %s found", e.prefix)
|
|
|
|
}
|
|
|
|
|
|
|
|
// A NoIDByPrefixError is returned by Find() when no ID for a given prefix
|
2016-08-31 22:39:36 +02:00
|
|
|
// could be found.
|
2020-11-10 22:43:18 +01:00
|
|
|
type NoIDByPrefixError struct{ prefix string }
|
2016-08-31 22:39:36 +02:00
|
|
|
|
2020-11-10 22:43:18 +01:00
|
|
|
func (e *NoIDByPrefixError) Error() string {
|
|
|
|
return fmt.Sprintf("no matching ID found for prefix %q", e.prefix)
|
|
|
|
}
|
2016-08-31 22:39:36 +02:00
|
|
|
|
|
|
|
// Find loads the list of all files 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.
|
2020-04-10 11:31:32 +02:00
|
|
|
func Find(ctx context.Context, be Lister, t FileType, prefix string) (string, error) {
|
2016-08-31 22:39:36 +02:00
|
|
|
match := ""
|
|
|
|
|
2020-04-10 11:31:32 +02:00
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
2018-01-20 13:43:07 +01:00
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
err := be.List(ctx, t, func(fi FileInfo) error {
|
2019-04-16 20:26:20 -07:00
|
|
|
if len(fi.Name) >= len(prefix) && prefix == fi.Name[:len(prefix)] {
|
2016-08-31 22:39:36 +02:00
|
|
|
if match == "" {
|
2018-01-20 13:43:07 +01:00
|
|
|
match = fi.Name
|
2016-08-31 22:39:36 +02:00
|
|
|
} else {
|
2020-11-10 22:43:18 +01:00
|
|
|
return &MultipleIDMatchesError{prefix}
|
2016-08-31 22:39:36 +02:00
|
|
|
}
|
|
|
|
}
|
2018-01-20 13:43:07 +01:00
|
|
|
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
2016-08-31 22:39:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if match != "" {
|
|
|
|
return match, nil
|
|
|
|
}
|
|
|
|
|
2020-11-10 22:43:18 +01:00
|
|
|
return "", &NoIDByPrefixError{prefix}
|
2016-08-31 22:39:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const minPrefixLength = 8
|
|
|
|
|
|
|
|
// PrefixLength returns the number of bytes required so that all prefixes of
|
|
|
|
// all names of type t are unique.
|
2020-04-10 11:31:32 +02:00
|
|
|
func PrefixLength(ctx context.Context, be Lister, t FileType) (int, error) {
|
2016-08-31 22:39:36 +02:00
|
|
|
// load all IDs of the given type
|
|
|
|
list := make([]string, 0, 100)
|
2018-01-20 13:43:07 +01:00
|
|
|
|
2020-04-10 11:31:32 +02:00
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
2018-01-20 13:43:07 +01:00
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
err := be.List(ctx, t, func(fi FileInfo) error {
|
|
|
|
list = append(list, fi.Name)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
2016-08-31 22:39:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// select prefixes of length l, test if the last one is the same as the current one
|
2020-03-07 00:04:47 +01:00
|
|
|
var id ID
|
2016-08-31 22:39:36 +02:00
|
|
|
outer:
|
2016-09-01 21:37:59 +02:00
|
|
|
for l := minPrefixLength; l < len(id); l++ {
|
2016-08-31 22:39:36 +02:00
|
|
|
var last string
|
|
|
|
|
|
|
|
for _, name := range list {
|
|
|
|
if last == name[:l] {
|
|
|
|
continue outer
|
|
|
|
}
|
|
|
|
last = name[:l]
|
|
|
|
}
|
|
|
|
|
|
|
|
return l, nil
|
|
|
|
}
|
|
|
|
|
2016-09-01 21:37:59 +02:00
|
|
|
return len(id), nil
|
2016-08-31 22:39:36 +02:00
|
|
|
}
|