blob: 8b1722e7db4ae47e429ba1aa055de23fb8004091 [file] [log] [blame]
package query
import (
"veyron/lib/glob"
"veyron/services/store/memstore/refs"
"veyron/services/store/memstore/state"
"veyron/services/store/service"
"veyron2/security"
"veyron2/storage"
)
type globIterator struct {
state.Iterator
pathLen int
glob *glob.Glob
}
// Glob returns an iterator that emits all values that match the given pattern.
func Glob(sn state.Snapshot, clientID security.PublicID, path storage.PathName, pattern string) (service.GlobStream, error) {
return GlobIterator(sn, clientID, path, pattern)
}
// GlobIterator returns an iterator that emits all values that match the given pattern.
func GlobIterator(sn state.Snapshot, clientID security.PublicID, path storage.PathName, pattern string) (state.Iterator, error) {
parsed, err := glob.Parse(pattern)
if err != nil {
return nil, err
}
g := &globIterator{
pathLen: len(path),
glob: parsed,
}
g.Iterator = sn.NewIterator(clientID, path, state.ListPaths, state.IterFilter(g.filter))
return g, nil
}
func (g *globIterator) filter(parent *refs.FullPath, path *refs.Path) (bool, bool) {
// We never get to a path unless we've first approved its parent.
// We can therefore only check a suffix of the glob pattern.
prefixLen := parent.Len() - g.pathLen
matched, suffix := g.glob.PartialMatch(prefixLen, []string(path.Name()))
return matched && suffix.Len() == 0, matched
}