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