77 "errors"
88 "os"
99 "path"
10+ "strings"
1011
1112 "github.com/spf13/afero"
1213 "go.mondoo.com/mql/v13/llx"
@@ -42,13 +43,7 @@ func (s *mqlFile) content(path string, exists bool) (string, error) {
4243 return string (res ), err
4344}
4445
45- func (s * mqlFile ) stat () error {
46- conn := s .MqlRuntime .Connection .(shared.Connection )
47- stat , err := conn .FileInfo (s .Path .Data )
48- if err != nil {
49- return err
50- }
51-
46+ func (s * mqlFile ) cacheStatFields (stat shared.FileInfoDetails ) error {
5247 mode := stat .Mode .UnixMode ()
5348 res , err := CreateResource (s .MqlRuntime , "file.permissions" , map [string ]* llx.RawData {
5449 "mode" : llx .IntData (int64 (uint32 (mode ) & 0o7777 )),
@@ -72,16 +67,65 @@ func (s *mqlFile) stat() error {
7267 return err
7368 }
7469
70+ s .Exists = plugin.TValue [bool ]{
71+ Data : true ,
72+ State : plugin .StateIsSet ,
73+ }
7574 s .Permissions = plugin.TValue [* mqlFilePermissions ]{
7675 Data : res .(* mqlFilePermissions ),
7776 State : plugin .StateIsSet ,
7877 }
79-
8078 s .Size = plugin.TValue [int64 ]{
8179 Data : stat .Size ,
8280 State : plugin .StateIsSet ,
8381 }
8482
83+ return nil
84+ }
85+
86+ func isFileNotFound (err error ) bool {
87+ if err == nil {
88+ return false
89+ }
90+ if errors .Is (err , os .ErrNotExist ) {
91+ return true
92+ }
93+
94+ errText := strings .ToLower (err .Error ())
95+ return strings .Contains (errText , "file not found" ) || strings .Contains (errText , "no such file or directory" )
96+ }
97+
98+
99+ func (s * mqlFile ) loadStatFields (path string ) (* shared.FileInfoDetails , bool , error ) {
100+ if s .Exists .IsSet () {
101+ if ! s .Exists .Data {
102+ return nil , false , s .Exists .Error
103+ }
104+ if s .Permissions .IsSet () && s .Size .IsSet () {
105+ return nil , true , nil
106+ }
107+ }
108+
109+ conn := s .MqlRuntime .Connection .(shared.Connection )
110+ stat , err := conn .FileInfo (path )
111+ if err != nil {
112+ if isFileNotFound (err ) {
113+ s .Exists = plugin.TValue [bool ]{
114+ Data : false ,
115+ State : plugin .StateIsSet ,
116+ }
117+ return nil , false , nil
118+ }
119+ return nil , false , err
120+ }
121+ if err := s .cacheStatFields (stat ); err != nil {
122+ return nil , false , err
123+ }
124+
125+ return & stat , true , nil
126+ }
127+
128+ func (s * mqlFile ) cacheOwnership (stat shared.FileInfoDetails ) error {
85129 raw , err := CreateResource (s .MqlRuntime , "users" , nil )
86130 if err != nil {
87131 return errors .New ("cannot get users info for file: " + err .Error ())
@@ -92,7 +136,6 @@ func (s *mqlFile) stat() error {
92136 if err != nil {
93137 return err
94138 }
95-
96139 s .User = plugin.TValue [* mqlUser ]{
97140 Data : user ,
98141 State : plugin .StateIsSet ,
@@ -108,7 +151,6 @@ func (s *mqlFile) stat() error {
108151 if err != nil {
109152 return err
110153 }
111-
112154 s .Group = plugin.TValue [* mqlGroup ]{
113155 Data : group ,
114156 State : plugin .StateIsSet ,
@@ -117,20 +159,61 @@ func (s *mqlFile) stat() error {
117159 return nil
118160}
119161
162+ func (s * mqlFile ) loadOwnership (path string ) error {
163+ stat , exists , err := s .loadStatFields (path )
164+ if err != nil {
165+ return err
166+ }
167+ if ! exists {
168+ return os .ErrNotExist
169+ }
170+ if s .User .IsSet () && s .Group .IsSet () {
171+ return nil
172+ }
173+ if stat == nil {
174+ conn := s .MqlRuntime .Connection .(shared.Connection )
175+ statValue , err := conn .FileInfo (path )
176+ if err != nil {
177+ return err
178+ }
179+ stat = & statValue
180+ }
181+
182+ return s .cacheOwnership (* stat )
183+ }
184+
185+ func (s * mqlFile ) stat () error {
186+ return s .loadOwnership (s .Path .Data )
187+ }
188+
120189func (s * mqlFile ) size (path string ) (int64 , error ) {
121- return 0 , s .stat ()
190+ _ , exists , err := s .loadStatFields (path )
191+ if err != nil {
192+ return 0 , err
193+ }
194+ if ! exists {
195+ return 0 , os .ErrNotExist
196+ }
197+ return 0 , nil
122198}
123199
124200func (s * mqlFile ) permissions (path string ) (* mqlFilePermissions , error ) {
125- return nil , s .stat ()
201+ _ , exists , err := s .loadStatFields (path )
202+ if err != nil {
203+ return nil , err
204+ }
205+ if ! exists {
206+ return nil , os .ErrNotExist
207+ }
208+ return nil , nil
126209}
127210
128211func (s * mqlFile ) user () (* mqlUser , error ) {
129- return nil , s .stat ( )
212+ return nil , s .loadOwnership ( s . Path . Data )
130213}
131214
132215func (s * mqlFile ) group () (* mqlGroup , error ) {
133- return nil , s .stat ( )
216+ return nil , s .loadOwnership ( s . Path . Data )
134217}
135218
136219func (s * mqlFile ) empty (path string ) (bool , error ) {
@@ -148,9 +231,8 @@ func (s *mqlFile) dirname(fullPath string) (string, error) {
148231}
149232
150233func (s * mqlFile ) exists (path string ) (bool , error ) {
151- conn := s .MqlRuntime .Connection .(shared.Connection )
152- afs := & afero.Afero {Fs : conn .FileSystem ()}
153- return afs .Exists (path )
234+ _ , exists , err := s .loadStatFields (path )
235+ return exists , err
154236}
155237
156238func (l * mqlFilePermissions ) id () (string , error ) {
0 commit comments