github.com/nextlinux/gosbom@v0.81.1-0.20230627115839-1ff50c281391/gosbom/file/cataloger/filedigest/cataloger.go (about) 1 package filedigest 2 3 import ( 4 "crypto" 5 "errors" 6 7 "github.com/nextlinux/gosbom/gosbom/event" 8 "github.com/nextlinux/gosbom/gosbom/file" 9 internal2 "github.com/nextlinux/gosbom/gosbom/file/cataloger/internal" 10 "github.com/nextlinux/gosbom/internal" 11 "github.com/nextlinux/gosbom/internal/bus" 12 "github.com/nextlinux/gosbom/internal/log" 13 "github.com/wagoodman/go-partybus" 14 "github.com/wagoodman/go-progress" 15 16 stereoscopeFile "github.com/anchore/stereoscope/pkg/file" 17 ) 18 19 var ErrUndigestableFile = errors.New("undigestable file") 20 21 type Cataloger struct { 22 hashes []crypto.Hash 23 } 24 25 func NewCataloger(hashes []crypto.Hash) *Cataloger { 26 return &Cataloger{ 27 hashes: hashes, 28 } 29 } 30 31 func (i *Cataloger) Catalog(resolver file.Resolver, coordinates ...file.Coordinates) (map[file.Coordinates][]file.Digest, error) { 32 results := make(map[file.Coordinates][]file.Digest) 33 var locations []file.Location 34 35 if len(coordinates) == 0 { 36 locations = internal2.AllRegularFiles(resolver) 37 } else { 38 for _, c := range coordinates { 39 locations = append(locations, file.NewLocationFromCoordinates(c)) 40 } 41 } 42 43 stage, prog := digestsCatalogingProgress(int64(len(locations))) 44 for _, location := range locations { 45 stage.Current = location.RealPath 46 result, err := i.catalogLocation(resolver, location) 47 48 if errors.Is(err, ErrUndigestableFile) { 49 continue 50 } 51 52 if internal.IsErrPathPermission(err) { 53 log.Debugf("file digests cataloger skipping %q: %+v", location.RealPath, err) 54 continue 55 } 56 57 if err != nil { 58 return nil, err 59 } 60 prog.Increment() 61 results[location.Coordinates] = result 62 } 63 log.Debugf("file digests cataloger processed %d files", prog.Current()) 64 prog.SetCompleted() 65 return results, nil 66 } 67 68 func (i *Cataloger) catalogLocation(resolver file.Resolver, location file.Location) ([]file.Digest, error) { 69 meta, err := resolver.FileMetadataByLocation(location) 70 if err != nil { 71 return nil, err 72 } 73 74 // we should only attempt to report digests for files that are regular files (don't attempt to resolve links) 75 if meta.Type != stereoscopeFile.TypeRegular { 76 return nil, ErrUndigestableFile 77 } 78 79 contentReader, err := resolver.FileContentsByLocation(location) 80 if err != nil { 81 return nil, err 82 } 83 defer internal.CloseAndLogError(contentReader, location.VirtualPath) 84 85 digests, err := file.NewDigestsFromFile(contentReader, i.hashes) 86 if err != nil { 87 return nil, internal.ErrPath{Context: "digests-cataloger", Path: location.RealPath, Err: err} 88 } 89 90 return digests, nil 91 } 92 93 func digestsCatalogingProgress(locations int64) (*progress.Stage, *progress.Manual) { 94 stage := &progress.Stage{} 95 prog := progress.NewManual(locations) 96 97 bus.Publish(partybus.Event{ 98 Type: event.FileDigestsCatalogerStarted, 99 Value: struct { 100 progress.Stager 101 progress.Progressable 102 }{ 103 Stager: progress.Stager(stage), 104 Progressable: prog, 105 }, 106 }) 107 108 return stage, prog 109 }