package vfs import ( "path" "strings" "fmt" ) // Find implements "$ find . -type f" for PWD=((fsys)). func Find(fsys FS, allowhidden bool, allowdirname, allowfilename func(string) bool) ([]string, error) { var filenames []string var dirnames []string dirnames = append(dirnames, ".") for len(dirnames) > 0 { dirname := dirnames[len(dirnames)-1] dirnames = dirnames[:len(dirnames)-1] entries, err := fsys.ReadDir(dirname) if err != nil { return nil, err } for _, entry := range entries { if strings.Contains(entry.Name(), "/") { return nil, fmt.Errorf("crooked entry in %q: %q", dirname, entry.Name()) } entryname := path.Join(dirname, entry.Name()) // entryname is clean, relative and not ".", so this checks precisely for hidden files if strings.HasPrefix(path.Base(entryname), ".") && !allowhidden { continue } info, err := entry.Info() if err != nil { return nil, fmt.Errorf("crooked entry %q: %v", entryname, err) } switch mode := info.Mode(); true { case mode.IsDir() && allowdirname(entryname): dirnames = append(dirnames, entryname) case mode.IsRegular() && allowfilename(entryname): filenames = append(filenames, entryname) } } } return filenames, nil }