@@ -5,10 +5,13 @@ package codesearch
55
66import (
77 "bytes"
8+ "errors"
89 "fmt"
910 "os"
1011 "path/filepath"
12+ "slices"
1113 "strings"
14+ "syscall"
1215
1316 "github.com/google/syzkaller/pkg/osutil"
1417)
@@ -26,6 +29,22 @@ type Command struct {
2629
2730// Commands are used to run unit tests and for the syz-codesearch tool.
2831var Commands = []Command {
32+ {"dir-index" , 1 , func (index * Index , args []string ) (string , error ) {
33+ ok , subdirs , files , err := index .DirIndex (args [0 ])
34+ if err != nil || ! ok {
35+ return notFound , err
36+ }
37+ b := new (strings.Builder )
38+ fmt .Fprintf (b , "directory %v subdirs:\n " , args [0 ])
39+ for _ , subdir := range subdirs {
40+ fmt .Fprintf (b , " - %v\n " , subdir )
41+ }
42+ fmt .Fprintf (b , "\n directory %v files:\n " , args [0 ])
43+ for _ , file := range files {
44+ fmt .Fprintf (b , " - %v\n " , file )
45+ }
46+ return b .String (), nil
47+ }},
2948 {"file-index" , 1 , func (index * Index , args []string ) (string , error ) {
3049 ok , entities , err := index .FileIndex (args [0 ])
3150 if err != nil || ! ok {
@@ -59,6 +78,8 @@ var Commands = []Command{
5978 }},
6079}
6180
81+ var SourceExtensions = map [string ]bool {".c" : true , ".h" : true , ".S" : true , ".rs" : true }
82+
6283const notFound = "not found\n "
6384
6485func NewIndex (databaseFile string , srcDirs []string ) (* Index , error ) {
@@ -90,6 +111,32 @@ type Entity struct {
90111 Name string
91112}
92113
114+ func (index * Index ) DirIndex (dir string ) (bool , []string , []string , error ) {
115+ if err := escaping (dir ); err != nil {
116+ return false , nil , nil , nil
117+ }
118+ exists := false
119+ var subdirs , files []string
120+ for _ , root := range index .srcDirs {
121+ exists1 , subdirs1 , files1 , err := dirIndex (root , dir )
122+ if err != nil {
123+ return false , nil , nil , err
124+ }
125+ if exists1 {
126+ exists = true
127+ }
128+ subdirs = append (subdirs , subdirs1 ... )
129+ files = append (files , files1 ... )
130+ }
131+ slices .Sort (subdirs )
132+ slices .Sort (files )
133+ // Dedup dirs across src/build trees,
134+ // also dedup files, but hopefully there are no duplicates.
135+ subdirs = slices .Compact (subdirs )
136+ files = slices .Compact (files )
137+ return exists , subdirs , files , nil
138+ }
139+
93140func (index * Index ) FileIndex (file string ) (bool , []Entity , error ) {
94141 var entities []Entity
95142 for _ , def := range index .db .Definitions {
@@ -188,3 +235,36 @@ func formatSourceFile(file string, start, end int, includeLines bool) (string, e
188235 }
189236 return b .String (), nil
190237}
238+
239+ func escaping (path string ) error {
240+ if strings .Contains (filepath .Clean (path ), ".." ) {
241+ return errors .New ("path is outside of the source tree" )
242+ }
243+ return nil
244+ }
245+
246+ func dirIndex (root , subdir string ) (bool , []string , []string , error ) {
247+ dir := filepath .Join (root , subdir )
248+ entries , err := os .ReadDir (dir )
249+ if err != nil {
250+ if os .IsNotExist (err ) {
251+ err = nil
252+ }
253+ var errno syscall.Errno
254+ if errors .As (err , & errno ) && errno == syscall .ENOTDIR {
255+ err = nil
256+ }
257+ return false , nil , nil , err
258+ }
259+ var subdirs , files []string
260+ for _ , entry := range entries {
261+ if strings .HasPrefix (entry .Name (), "." ) {
262+ // These are internal things like .git, etc.
263+ } else if entry .IsDir () {
264+ subdirs = append (subdirs , entry .Name ())
265+ } else if SourceExtensions [filepath .Ext (entry .Name ())] {
266+ files = append (files , entry .Name ())
267+ }
268+ }
269+ return true , subdirs , files , err
270+ }
0 commit comments