Skip to content

Commit ce7d92e

Browse files
authored
🧹 refactor files find for better readability (#6316)
* 🧹 refactor files file resource * 🧹 extract find cmd generator into its own package
1 parent d192028 commit ce7d92e

File tree

3 files changed

+175
-101
lines changed

3 files changed

+175
-101
lines changed

providers/os/resources/files.go

Lines changed: 78 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,17 @@ package resources
66

77
import (
88
"errors"
9-
"fmt"
109
"regexp"
1110
"strconv"
1211
"strings"
1312

13+
"github.com/rs/zerolog/log"
1414
"go.mondoo.com/cnquery/v12/llx"
1515
"go.mondoo.com/cnquery/v12/providers-sdk/v1/plugin"
1616
"go.mondoo.com/cnquery/v12/providers/os/connection/shared"
17+
"go.mondoo.com/cnquery/v12/providers/os/resources/filesfind"
1718
)
1819

19-
var findTypes = map[string]string{
20-
"file": "f",
21-
"directory": "d",
22-
"character": "c",
23-
"block": "b",
24-
"socket": "s",
25-
"link": "l",
26-
}
27-
2820
func initFilesFind(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) {
2921
if args["permissions"] == nil {
3022
args["permissions"] = llx.IntData(int64(0o777))
@@ -33,10 +25,6 @@ func initFilesFind(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[s
3325
return args, nil, nil
3426
}
3527

36-
func octal2string(o int64) string {
37-
return fmt.Sprintf("%o", o)
38-
}
39-
4028
func (l *mqlFilesFind) id() (string, error) {
4129
var id strings.Builder
4230
id.WriteString(l.From.Data)
@@ -61,109 +49,31 @@ func (l *mqlFilesFind) id() (string, error) {
6149
}
6250

6351
if l.Permissions.Data != 0o777 {
64-
id.WriteString(" permissions=" + octal2string(l.Permissions.Data))
52+
id.WriteString(" permissions=" + filesfind.Octal2string(l.Permissions.Data))
6553
}
6654

6755
return id.String(), nil
6856
}
6957

7058
func (l *mqlFilesFind) list() ([]any, error) {
7159
var err error
72-
var compiledRegexp *regexp.Regexp
73-
if len(l.Regex.Data) > 0 {
74-
compiledRegexp, err = regexp.Compile(l.Regex.Data)
75-
if err != nil {
76-
return nil, err
77-
}
78-
} else if len(l.Name.Data) > 0 {
79-
compiledRegexp, err = regexp.Compile(l.Name.Data)
80-
if err != nil {
81-
return nil, err
82-
}
83-
}
84-
8560
var foundFiles []string
8661
conn := l.MqlRuntime.Connection.(shared.Connection)
87-
if conn.Capabilities().Has(shared.Capability_FindFile) {
88-
fs := conn.FileSystem()
89-
fsSearch, ok := fs.(shared.FileSearch)
90-
if !ok {
91-
return nil, errors.New("find is not supported for your platform")
92-
}
93-
94-
var perm *uint32
95-
if l.Permissions.Data != 0o777 {
96-
p := uint32(l.Permissions.Data)
97-
perm = &p
98-
}
99-
100-
var depth *int
101-
if l.Depth.IsSet() {
102-
d := int(l.Depth.Data)
103-
depth = &d
104-
}
62+
pf := conn.Asset().Platform
63+
if pf == nil {
64+
return nil, errors.New("missing platform information")
65+
}
10566

106-
foundFiles, err = fsSearch.Find(l.From.Data, compiledRegexp, l.Type.Data, perm, depth)
67+
if conn.Capabilities().Has(shared.Capability_FindFile) {
68+
foundFiles, err = l.fsFilesFind(conn)
10769
if err != nil {
10870
return nil, err
10971
}
110-
} else if conn.Capabilities().Has(shared.Capability_RunCommand) {
111-
var call strings.Builder
112-
call.WriteString("find -L ")
113-
call.WriteString(strconv.Quote(l.From.Data))
114-
115-
if !l.Xdev.Data {
116-
call.WriteString(" -xdev")
117-
}
118-
119-
if l.Type.Data != "" {
120-
t, ok := findTypes[l.Type.Data]
121-
if ok {
122-
call.WriteString(" -type " + t)
123-
}
124-
}
125-
126-
if l.Regex.Data != "" {
127-
// TODO: we need to escape regex here
128-
call.WriteString(" -regex '")
129-
call.WriteString(l.Regex.Data)
130-
call.WriteString("'")
131-
}
132-
133-
if l.Permissions.Data != 0o777 {
134-
call.WriteString(" -perm -")
135-
call.WriteString(octal2string(l.Permissions.Data))
136-
}
137-
138-
if l.Name.Data != "" {
139-
call.WriteString(" -name ")
140-
call.WriteString(l.Name.Data)
141-
}
142-
143-
if l.Depth.IsSet() {
144-
call.WriteString(" -maxdepth ")
145-
call.WriteString(octal2string(l.Depth.Data))
146-
}
147-
148-
rawCmd, err := CreateResource(l.MqlRuntime, "command", map[string]*llx.RawData{
149-
"command": llx.StringData(call.String()),
150-
})
72+
} else if conn.Capabilities().Has(shared.Capability_RunCommand) && pf.IsFamily("unix") {
73+
foundFiles, err = l.unixFilesFindCmd()
15174
if err != nil {
15275
return nil, err
15376
}
154-
155-
cmd := rawCmd.(*mqlCommand)
156-
out := cmd.GetStdout()
157-
if out.Error != nil {
158-
return nil, out.Error
159-
}
160-
161-
lines := strings.TrimSpace(out.Data)
162-
if lines == "" {
163-
foundFiles = []string{}
164-
} else {
165-
foundFiles = strings.Split(lines, "\n")
166-
}
16777
} else {
16878
return nil, errors.New("find is not supported for your platform")
16979
}
@@ -183,3 +93,70 @@ func (l *mqlFilesFind) list() ([]any, error) {
18393
// return the packages as new entries
18494
return files, nil
18595
}
96+
97+
func (l *mqlFilesFind) fsFilesFind(conn shared.Connection) ([]string, error) {
98+
log.Debug().Msgf("use native files find approach")
99+
fs := conn.FileSystem()
100+
fsSearch, ok := fs.(shared.FileSearch)
101+
if !ok {
102+
return nil, errors.New("find is not supported for your platform")
103+
}
104+
105+
var perm *uint32
106+
if l.Permissions.Data != 0o777 {
107+
p := uint32(l.Permissions.Data)
108+
perm = &p
109+
}
110+
111+
var depth *int
112+
if l.Depth.IsSet() {
113+
d := int(l.Depth.Data)
114+
depth = &d
115+
}
116+
117+
var compiledRegexp *regexp.Regexp
118+
var err error
119+
if len(l.Regex.Data) > 0 {
120+
compiledRegexp, err = regexp.Compile(l.Regex.Data)
121+
if err != nil {
122+
return nil, err
123+
}
124+
} else if len(l.Name.Data) > 0 {
125+
compiledRegexp, err = regexp.Compile(l.Name.Data)
126+
if err != nil {
127+
return nil, err
128+
}
129+
}
130+
131+
return fsSearch.Find(l.From.Data, compiledRegexp, l.Type.Data, perm, depth)
132+
}
133+
134+
func (l *mqlFilesFind) unixFilesFindCmd() ([]string, error) {
135+
var depth *int64
136+
if l.Depth.IsSet() {
137+
depth = &l.Depth.Data
138+
}
139+
140+
callCmd := filesfind.BuildFilesFindCmd(l.From.Data, l.Xdev.Data, l.Type.Data, l.Regex.Data, l.Permissions.Data, l.Name.Data, depth)
141+
rawCmd, err := CreateResource(l.MqlRuntime, "command", map[string]*llx.RawData{
142+
"command": llx.StringData(callCmd),
143+
})
144+
if err != nil {
145+
return nil, err
146+
}
147+
148+
cmd := rawCmd.(*mqlCommand)
149+
out := cmd.GetStdout()
150+
if out.Error != nil {
151+
return nil, out.Error
152+
}
153+
154+
var foundFiles []string
155+
lines := strings.TrimSpace(out.Data)
156+
if lines == "" {
157+
foundFiles = []string{}
158+
} else {
159+
foundFiles = strings.Split(lines, "\n")
160+
}
161+
return foundFiles, nil
162+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Copyright (c) Mondoo, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
4+
package filesfind
5+
6+
import (
7+
"fmt"
8+
"strconv"
9+
"strings"
10+
)
11+
12+
var findTypes = map[string]string{
13+
"file": "f",
14+
"directory": "d",
15+
"character": "c",
16+
"block": "b",
17+
"socket": "s",
18+
"link": "l",
19+
}
20+
21+
func Octal2string(o int64) string {
22+
return fmt.Sprintf("%o", o)
23+
}
24+
25+
func BuildFilesFindCmd(from string, xdev bool, fileType string, regex string, permission int64, search string, depth *int64) string {
26+
var call strings.Builder
27+
call.WriteString("find -L ")
28+
call.WriteString(strconv.Quote(from))
29+
30+
if !xdev {
31+
call.WriteString(" -xdev")
32+
}
33+
34+
if fileType != "" {
35+
t, ok := findTypes[fileType]
36+
if ok {
37+
call.WriteString(" -type " + t)
38+
}
39+
}
40+
41+
if regex != "" {
42+
// TODO: we need to escape regex here
43+
call.WriteString(" -regex '")
44+
call.WriteString(regex)
45+
call.WriteString("'")
46+
}
47+
48+
if permission != 0o777 {
49+
call.WriteString(" -perm -")
50+
call.WriteString(Octal2string(permission))
51+
}
52+
53+
if search != "" {
54+
call.WriteString(" -name ")
55+
call.WriteString(search)
56+
}
57+
58+
if depth != nil {
59+
call.WriteString(" -maxdepth ")
60+
call.WriteString(Octal2string(*depth))
61+
}
62+
return call.String()
63+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) Mondoo, Inc.
2+
// SPDX-License-Identifier: BUSL-1.1
3+
4+
package filesfind
5+
6+
import (
7+
"testing"
8+
9+
"github.com/stretchr/testify/assert"
10+
)
11+
12+
func TestUnixFilesCmdGeneration(t *testing.T) {
13+
tests := []struct {
14+
From string
15+
Xdev bool
16+
FileType string
17+
Regex string
18+
Permission int64
19+
Search string
20+
Depth *int64
21+
ExpectedCmd string
22+
}{
23+
{
24+
From: "/Users/john/.aws",
25+
FileType: "file",
26+
ExpectedCmd: "find -L \"/Users/john/.aws\" -xdev -type f -perm -0",
27+
},
28+
}
29+
30+
for _, tt := range tests {
31+
cmd := BuildFilesFindCmd(tt.From, tt.Xdev, tt.FileType, tt.Regex, tt.Permission, tt.Search, tt.Depth)
32+
assert.Equal(t, tt.ExpectedCmd, cmd)
33+
}
34+
}

0 commit comments

Comments
 (0)