126 lines
2.6 KiB
Go
126 lines
2.6 KiB
Go
|
package paths
|
||
|
|
||
|
import (
|
||
|
`io/fs`
|
||
|
`os`
|
||
|
`path/filepath`
|
||
|
`time`
|
||
|
|
||
|
`github.com/djherbis/times`
|
||
|
`r00t2.io/goutils/bitmask`
|
||
|
)
|
||
|
|
||
|
/*
|
||
|
Match returns match (a ptr to a FsSearchResult if the specified path matches, otherwise nil),
|
||
|
miss (ptr the specified path does not match, otherwise nil), and an fs.DirEntry and fs.FileInfo
|
||
|
for path. d and/or fi may be nil.
|
||
|
|
||
|
If err is not nil, it represents an unexpected error and as such, both match and miss should be nil.
|
||
|
|
||
|
Match, miss, and err will all be nil if the filesystem object/path does not exist.
|
||
|
*/
|
||
|
func (f *FsSearchCriteria) Match(path string, d fs.DirEntry, fi fs.FileInfo) (match, miss *FsSearchResult, err error) {
|
||
|
|
||
|
var typeMode fs.FileMode
|
||
|
var m FsSearchResult
|
||
|
var typeFilter *bitmask.MaskBit = bitmask.NewMaskBitExplicit(uint(f.TargetType))
|
||
|
|
||
|
m = FsSearchResult{
|
||
|
Path: path,
|
||
|
DirEntry: d,
|
||
|
FileInfo: fi,
|
||
|
Criteria: f,
|
||
|
}
|
||
|
|
||
|
if f == nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// A DirEntry can be created from a FileInfo but not vice versa.
|
||
|
if m.FileInfo == nil {
|
||
|
if m.DirEntry != nil {
|
||
|
if m.FileInfo, err = m.DirEntry.Info(); err != nil {
|
||
|
err = filterNoFileDir(err)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
if f.FollowSymlinks {
|
||
|
if m.FileInfo, err = os.Stat(path); err != nil {
|
||
|
err = filterNoFileDir(err)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
if m.FileInfo, err = os.Lstat(path); err != nil {
|
||
|
err = filterNoFileDir(err)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
m.DirEntry = fs.FileInfoToDirEntry(m.FileInfo)
|
||
|
}
|
||
|
}
|
||
|
if m.DirEntry == nil {
|
||
|
m.DirEntry = fs.FileInfoToDirEntry(m.FileInfo)
|
||
|
}
|
||
|
if m.DirEntry == nil || m.FileInfo == nil {
|
||
|
m.MissReason = MissNoMeta
|
||
|
miss = &m
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if m.Times, err = times.Stat(path); err != nil {
|
||
|
err = filterNoFileDir(err)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if f.PathPtrn != nil && !f.PathPtrn.MatchString(path) {
|
||
|
m.MissReason = MissBadPath
|
||
|
miss = &m
|
||
|
return
|
||
|
}
|
||
|
if f.BasePtrn != nil && !f.BasePtrn.MatchString(filepath.Base(path)) {
|
||
|
m.MissReason = MissBadBase
|
||
|
miss = &m
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// age
|
||
|
if f.Age != nil {
|
||
|
if f.Now == nil {
|
||
|
f.Now = new(time.Time)
|
||
|
*f.Now = time.Now()
|
||
|
}
|
||
|
if !filterTimes(m.Times, f.Age, &f.AgeType, f.OlderThan, f.Now) {
|
||
|
m.MissReason = MissBadTime
|
||
|
miss = &m
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// fs object type (file, dir, etc.)
|
||
|
typeMode = m.FileInfo.Mode().Type()
|
||
|
if typeMode == 0 && f.NoFiles {
|
||
|
m.MissReason = MissFile
|
||
|
miss = &m
|
||
|
return
|
||
|
} else if typeMode != 0 {
|
||
|
if !typeFilter.HasFlag(bitmask.MaskBit(typeMode)) {
|
||
|
m.MissReason = MissType
|
||
|
miss = &m
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If it gets to here, it matches.
|
||
|
match = &m
|
||
|
|
||
|
return
|
||
|
}
|