github.com/fawick/restic@v0.1.1-0.20171126184616-c02923fbfc79/internal/restic/backend_find.go (about)

     1  package restic
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/restic/restic/internal/errors"
     7  )
     8  
     9  // ErrNoIDPrefixFound is returned by Find() when no ID for the given prefix
    10  // could be found.
    11  var ErrNoIDPrefixFound = errors.New("no ID found")
    12  
    13  // ErrMultipleIDMatches is returned by Find() when multiple IDs with the given
    14  // prefix are found.
    15  var ErrMultipleIDMatches = errors.New("multiple IDs with prefix found")
    16  
    17  // Find loads the list of all files of type t and searches for names which
    18  // start with prefix. If none is found, nil and ErrNoIDPrefixFound is returned.
    19  // If more than one is found, nil and ErrMultipleIDMatches is returned.
    20  func Find(be Lister, t FileType, prefix string) (string, error) {
    21  	match := ""
    22  
    23  	// TODO: optimize by sorting list etc.
    24  	for name := range be.List(context.TODO(), t) {
    25  		if prefix == name[:len(prefix)] {
    26  			if match == "" {
    27  				match = name
    28  			} else {
    29  				return "", ErrMultipleIDMatches
    30  			}
    31  		}
    32  	}
    33  
    34  	if match != "" {
    35  		return match, nil
    36  	}
    37  
    38  	return "", ErrNoIDPrefixFound
    39  }
    40  
    41  const minPrefixLength = 8
    42  
    43  // PrefixLength returns the number of bytes required so that all prefixes of
    44  // all names of type t are unique.
    45  func PrefixLength(be Lister, t FileType) (int, error) {
    46  	// load all IDs of the given type
    47  	list := make([]string, 0, 100)
    48  	for name := range be.List(context.TODO(), t) {
    49  		list = append(list, name)
    50  	}
    51  
    52  	// select prefixes of length l, test if the last one is the same as the current one
    53  	id := ID{}
    54  outer:
    55  	for l := minPrefixLength; l < len(id); l++ {
    56  		var last string
    57  
    58  		for _, name := range list {
    59  			if last == name[:l] {
    60  				continue outer
    61  			}
    62  			last = name[:l]
    63  		}
    64  
    65  		return l, nil
    66  	}
    67  
    68  	return len(id), nil
    69  }