From b28be74cde9c5d5c857775f5cf4a8cee6604db74 Mon Sep 17 00:00:00 2001 From: Evan Maddock Date: Tue, 5 Sep 2023 11:45:11 -0400 Subject: [PATCH] state: Don't recurse infinitely into subdirectories This fixes the issue where potentially the entire /usr/lib tree is added to the state map, adding hundreds of thousands of entries. This attempts to only recurse one subdirectory to try to match what the C usysconf did. With this commit, a first run only adds roughly 6200 entries. Still far higher than previous usysconf's 400, but at least it doesn't choke on a second run. Signed-off-by: Evan Maddock --- state/map.go | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/state/map.go b/state/map.go index 8122205..4f5f02a 100644 --- a/state/map.go +++ b/state/map.go @@ -16,6 +16,7 @@ package state import ( "fmt" + "io/fs" "log/slog" "os" "path/filepath" @@ -76,6 +77,7 @@ func (m Map) Save() error { // Merge combines two Maps into one func (m Map) Merge(other Map) { for k, v := range other { + slog.Debug("merging to state", "key", k) m[k] = v } } @@ -166,31 +168,53 @@ func (m Map) Strings() (strs []string) { func Scan(filters []string) (m Map, err error) { m = make(Map) var matches []string + for _, filter := range filters { if matches, err = filepath.Glob(filter); err != nil { err = fmt.Errorf("unable to glob path: %s", filter) return } + if len(matches) == 0 { continue } + for _, match := range matches { - err = filepath.Walk(filepath.Clean(match), func(path string, info os.FileInfo, err error) error { + dirCount := strings.Count(filepath.Clean(match), string(os.PathSeparator)) + + err = filepath.WalkDir(filepath.Clean(match), func(path string, d fs.DirEntry, err error) error { if err != nil { - err = fmt.Errorf("failed to check path: %s", path) return err } - m[filepath.Join(path, info.Name())] = info.ModTime() + + // We do not want to walk the entire tree + maxDepth := dirCount + 1 + if strings.Count(path, string(os.PathSeparator)) > maxDepth { + err = fs.SkipDir + return err + } + + // Get the file info + info, err := d.Info() + if err != nil { + return err + } + + // Add it to the state map + m[path] = info.ModTime() return nil }) + if err != nil { if os.IsNotExist(err) { err = nil continue } + return } } } + return }