Files
trivy/pkg/fanal/utils/utils.go
Matthieu MOREL a19e0aa1ba fix: octalLiteral from go-critic (#8811)
Signed-off-by: Matthieu MOREL <matthieu.morel35@gmail.com>
2025-05-05 13:49:07 +00:00

142 lines
3.2 KiB
Go

package utils
import (
"bufio"
"bytes"
"fmt"
"io"
"math"
"os"
"os/exec"
"path/filepath"
"strings"
"unicode"
"github.com/bmatcuk/doublestar/v4"
"github.com/samber/lo"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/log"
xio "github.com/aquasecurity/trivy/pkg/x/io"
)
var PathSeparator = fmt.Sprintf("%c", os.PathSeparator)
func CacheDir() string {
cacheDir, err := os.UserCacheDir()
if err != nil {
cacheDir = os.TempDir()
}
return cacheDir
}
func IsCommandAvailable(name string) bool {
if _, err := exec.LookPath(name); err != nil {
return false
}
return true
}
func IsGzip(f *bufio.Reader) bool {
buf, err := f.Peek(3)
if err != nil {
return false
}
return buf[0] == 0x1F && buf[1] == 0x8B && buf[2] == 0x8
}
func IsExecutable(fileInfo os.FileInfo) bool {
// For Windows
if filepath.Ext(fileInfo.Name()) == ".exe" {
return true
}
mode := fileInfo.Mode()
if !mode.IsRegular() {
return false
}
// Check unpackaged file
if mode.Perm()&0o111 != 0 {
return true
}
return false
}
func IsBinary(content xio.ReadSeekerAt, fileSize int64) (bool, error) {
headSize := int(math.Min(float64(fileSize), 300))
head := make([]byte, headSize)
if _, err := content.Read(head); err != nil {
return false, err
}
if _, err := content.Seek(0, io.SeekStart); err != nil {
return false, err
}
// cf. https://github.com/file/file/blob/f2a6e7cb7db9b5fd86100403df6b2f830c7f22ba/src/encoding.c#L151-L228
for _, b := range head {
if b < 7 || b == 11 || (13 < b && b < 27) || (27 < b && b < 0x20) || b == 0x7f {
return true, nil
}
}
return false, nil
}
func CleanSkipPaths(skipPaths []string) []string {
return lo.Map(skipPaths, func(skipPath string, _ int) string {
skipPath = filepath.ToSlash(filepath.Clean(skipPath))
return strings.TrimLeft(skipPath, "/")
})
}
func SkipPath(path string, skipPaths []string) bool {
path = strings.TrimLeft(path, "/")
// skip files
for _, pattern := range skipPaths {
match, err := doublestar.Match(pattern, path)
if err != nil {
return false // return early if bad pattern
} else if match {
log.Debug("Skipping path", log.String("path", path))
return true
}
}
return false
}
func ExtractPrintableBytes(content xio.ReadSeekerAt) ([]byte, error) {
const minLength = 4 // Minimum length of strings to extract
var result []byte
currentPrintableLine := new(bytes.Buffer)
current := make([]byte, 1) // buffer for 1 byte reading
for {
if n, err := content.Read(current); err == io.EOF {
break
} else if n != 1 {
continue
} else if err != nil {
return nil, xerrors.Errorf("failed to read a byte: %w", err)
}
if unicode.IsPrint(rune(current[0])) {
_ = currentPrintableLine.WriteByte(current[0])
continue
}
if currentPrintableLine.Len() > minLength {
// add a newline between printable lines to separate them
_ = currentPrintableLine.WriteByte('\n')
result = append(result, currentPrintableLine.Bytes()...)
}
currentPrintableLine.Reset()
}
if currentPrintableLine.Len() > minLength {
// add a newline between printable lines to separate them
_ = currentPrintableLine.WriteByte('\n')
result = append(result, currentPrintableLine.Bytes()...)
}
return result, nil
}