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