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