restic/internal/restic/backend_find.go

103 lines
2.3 KiB
Go
Raw Normal View History

2016-08-31 20:39:36 +00:00
package restic
2017-06-03 15:39:57 +00:00
import (
"context"
"fmt"
"github.com/restic/restic/internal/debug"
2017-06-03 15:39:57 +00:00
)
2016-08-31 20:39:36 +00: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 {
2021-08-25 14:11:28 +00:00
return fmt.Sprintf("multiple IDs with prefix %q found", e.prefix)
}
// A NoIDByPrefixError is returned by Find() when no ID for a given prefix
2016-08-31 20:39:36 +00:00
// could be found.
type NoIDByPrefixError struct{ prefix string }
2016-08-31 20:39:36 +00:00
func (e *NoIDByPrefixError) Error() string {
return fmt.Sprintf("no matching ID found for prefix %q", e.prefix)
}
2016-08-31 20:39:36 +00: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.
func Find(ctx context.Context, be Lister, t FileType, prefix string) (string, error) {
2016-08-31 20:39:36 +00:00
match := ""
ctx, cancel := context.WithCancel(ctx)
defer cancel()
err := be.List(ctx, t, func(fi FileInfo) error {
// ignore filename which are not an id
_, err := ParseID(fi.Name)
if err != nil {
debug.Log("unable to parse %v as an ID", fi.Name)
return nil
}
if len(fi.Name) >= len(prefix) && prefix == fi.Name[:len(prefix)] {
2016-08-31 20:39:36 +00:00
if match == "" {
match = fi.Name
2016-08-31 20:39:36 +00:00
} else {
return &MultipleIDMatchesError{prefix}
2016-08-31 20:39:36 +00:00
}
}
return nil
})
if err != nil {
return "", err
2016-08-31 20:39:36 +00:00
}
if match != "" {
return match, nil
}
return "", &NoIDByPrefixError{prefix}
2016-08-31 20:39:36 +00:00
}
const minPrefixLength = 8
// PrefixLength returns the number of bytes required so that all prefixes of
// all names of type t are unique.
func PrefixLength(ctx context.Context, be Lister, t FileType) (int, error) {
2016-08-31 20:39:36 +00:00
// load all IDs of the given type
list := make([]string, 0, 100)
ctx, cancel := context.WithCancel(ctx)
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 20:39:36 +00:00
}
// select prefixes of length l, test if the last one is the same as the current one
2020-03-06 23:04:47 +00:00
var id ID
2016-08-31 20:39:36 +00:00
outer:
for l := minPrefixLength; l < len(id); l++ {
2016-08-31 20:39:36 +00:00
var last string
for _, name := range list {
if last == name[:l] {
continue outer
}
last = name[:l]
}
return l, nil
}
return len(id), nil
2016-08-31 20:39:36 +00:00
}