go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/resources/files.go (about) 1 // copyright: 2020, Dominik Richter and Christoph Hartmann 2 // author: Dominik Richter 3 // author: Christoph Hartmann 4 5 package resources 6 7 import ( 8 "errors" 9 "fmt" 10 "regexp" 11 "strconv" 12 "strings" 13 14 "go.mondoo.com/cnquery/llx" 15 "go.mondoo.com/cnquery/providers-sdk/v1/plugin" 16 "go.mondoo.com/cnquery/providers/os/connection/shared" 17 ) 18 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 28 func initFilesFind(runtime *plugin.Runtime, args map[string]*llx.RawData) (map[string]*llx.RawData, plugin.Resource, error) { 29 if args["permissions"] == nil { 30 args["permissions"] = llx.IntData(int64(0o777)) 31 } 32 33 return args, nil, nil 34 } 35 36 func octal2string(o int64) string { 37 return fmt.Sprintf("%o", o) 38 } 39 40 func (l *mqlFilesFind) id() (string, error) { 41 var id strings.Builder 42 id.WriteString(l.From.Data) 43 if !l.Xdev.Data { 44 id.WriteString(" -xdev") 45 } 46 if l.Type.Data != "" { 47 id.WriteString(" type=" + l.Type.Data) 48 } 49 50 if l.Regex.Data != "" { 51 id.WriteString(" regex=" + l.Regex.Data) 52 } 53 54 if l.Name.Data != "" { 55 id.WriteString(" name=" + l.Name.Data) 56 } 57 58 if l.Permissions.Data != 0o777 { 59 id.WriteString(" permissions=" + octal2string(l.Permissions.Data)) 60 } 61 62 return id.String(), nil 63 } 64 65 func (l *mqlFilesFind) list() ([]interface{}, error) { 66 var err error 67 var compiledRegexp *regexp.Regexp 68 if len(l.Regex.Data) > 0 { 69 compiledRegexp, err = regexp.Compile(l.Regex.Data) 70 if err != nil { 71 return nil, err 72 } 73 } 74 75 var foundFiles []string 76 conn := l.MqlRuntime.Connection.(shared.Connection) 77 if conn.Capabilities().Has(shared.Capability_FindFile) { 78 fs := conn.FileSystem() 79 fsSearch, ok := fs.(shared.FileSearch) 80 if !ok { 81 return nil, errors.New("find is not supported for your platform") 82 } 83 84 foundFiles, err = fsSearch.Find(l.From.Data, compiledRegexp, l.Type.Data) 85 if err != nil { 86 return nil, err 87 } 88 } else if conn.Capabilities().Has(shared.Capability_RunCommand) { 89 var call strings.Builder 90 call.WriteString("find -L ") 91 call.WriteString(strconv.Quote(l.From.Data)) 92 93 if !l.Xdev.Data { 94 call.WriteString(" -xdev") 95 } 96 97 if l.Type.Data != "" { 98 t, ok := findTypes[l.Type.Data] 99 if ok { 100 call.WriteString(" -type " + t) 101 } 102 } 103 104 if l.Regex.Data != "" { 105 // TODO: we need to escape regex here 106 call.WriteString(" -regex '") 107 call.WriteString(l.Regex.Data) 108 call.WriteString("'") 109 } 110 111 if l.Permissions.Data != 0o777 { 112 call.WriteString(" -perm -") 113 call.WriteString(octal2string(l.Permissions.Data)) 114 } 115 116 if l.Name.Data != "" { 117 call.WriteString(" -name ") 118 call.WriteString(l.Name.Data) 119 } 120 121 rawCmd, err := CreateResource(l.MqlRuntime, "command", map[string]*llx.RawData{ 122 "command": llx.StringData(call.String()), 123 }) 124 if err != nil { 125 return nil, err 126 } 127 128 cmd := rawCmd.(*mqlCommand) 129 out := cmd.GetStdout() 130 if out.Error != nil { 131 return nil, out.Error 132 } 133 134 lines := strings.TrimSpace(out.Data) 135 if lines == "" { 136 foundFiles = []string{} 137 } else { 138 foundFiles = strings.Split(lines, "\n") 139 } 140 } else { 141 return nil, errors.New("find is not supported for your platform") 142 } 143 144 files := make([]interface{}, len(foundFiles)) 145 var filepath string 146 for i := range foundFiles { 147 filepath = foundFiles[i] 148 files[i], err = CreateResource(l.MqlRuntime, "file", map[string]*llx.RawData{ 149 "path": llx.StringData(filepath), 150 }) 151 if err != nil { 152 return nil, err 153 } 154 } 155 156 // return the packages as new entries 157 return files, nil 158 }