github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/pkg/cataloger/redhat/parse_rpm_archive.go (about) 1 package redhat 2 3 import ( 4 "context" 5 "fmt" 6 "strconv" 7 8 rpmdb "github.com/knqyf263/go-rpmdb/pkg" 9 "github.com/sassoftware/go-rpmutils" 10 11 "github.com/anchore/syft/syft/artifact" 12 "github.com/anchore/syft/syft/file" 13 "github.com/anchore/syft/syft/pkg" 14 "github.com/anchore/syft/syft/pkg/cataloger/generic" 15 ) 16 17 // parseRpmArchive parses a single RPM 18 func parseRpmArchive(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { 19 rpm, err := rpmutils.ReadRpm(reader) 20 if err != nil { 21 return nil, nil, fmt.Errorf("RPM file found but unable to read: %s (%w)", reader.Location.RealPath, err) 22 } 23 24 nevra, err := rpm.Header.GetNEVRA() 25 if err != nil { 26 return nil, nil, err 27 } 28 29 licenses, _ := rpm.Header.GetStrings(rpmutils.LICENSE) 30 sourceRpm, _ := rpm.Header.GetString(rpmutils.SOURCERPM) 31 vendor, _ := rpm.Header.GetString(rpmutils.VENDOR) 32 digestAlgorithm := getDigestAlgorithm(rpm.Header) 33 size, _ := rpm.Header.InstalledSize() 34 files, _ := rpm.Header.GetFiles() 35 36 metadata := pkg.RpmArchive{ 37 Name: nevra.Name, 38 Version: nevra.Version, 39 Epoch: parseEpoch(nevra.Epoch), 40 Arch: nevra.Arch, 41 Release: nevra.Release, 42 SourceRpm: sourceRpm, 43 Vendor: vendor, 44 Size: int(size), 45 Files: mapFiles(files, digestAlgorithm), 46 } 47 48 return []pkg.Package{newArchivePackage(reader.Location, metadata, licenses)}, nil, nil 49 } 50 51 func getDigestAlgorithm(header *rpmutils.RpmHeader) string { 52 digestAlgorithm, _ := header.GetString(rpmutils.FILEDIGESTALGO) 53 if digestAlgorithm != "" { 54 return digestAlgorithm 55 } 56 digestAlgorithms, _ := header.GetUint32s(rpmutils.FILEDIGESTALGO) 57 if len(digestAlgorithms) > 0 { 58 digestAlgo := int(digestAlgorithms[0]) 59 return rpmutils.GetFileAlgoName(digestAlgo) 60 } 61 return "" 62 } 63 64 func mapFiles(files []rpmutils.FileInfo, digestAlgorithm string) []pkg.RpmFileRecord { 65 var out []pkg.RpmFileRecord 66 for _, f := range files { 67 digest := file.Digest{} 68 if f.Digest() != "" { 69 digest = file.Digest{ 70 Algorithm: digestAlgorithm, 71 Value: f.Digest(), 72 } 73 } 74 out = append(out, pkg.RpmFileRecord{ 75 Path: f.Name(), 76 Mode: pkg.RpmFileMode(f.Mode()), 77 Size: int(f.Size()), 78 Digest: digest, 79 UserName: f.UserName(), 80 GroupName: f.GroupName(), 81 Flags: rpmdb.FileFlags(f.Flags()).String(), 82 }) 83 } 84 return out 85 } 86 87 func parseEpoch(epoch string) *int { 88 i, err := strconv.Atoi(epoch) 89 if err != nil { 90 return nil 91 } 92 return &i 93 }