github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/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/syft/event" 12 "github.com/anchore/syft/syft/file" 13 "github.com/lineaje-labs/syft/internal" 14 "github.com/lineaje-labs/syft/internal/bus" 15 intFile "github.com/lineaje-labs/syft/internal/file" 16 "github.com/lineaje-labs/syft/internal/log" 17 intCataloger "github.com/lineaje-labs/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( 33 resolver file.Resolver, coordinates ...file.Coordinates, 34 ) (map[file.Coordinates][]file.Digest, error) { 35 results := make(map[file.Coordinates][]file.Digest) 36 var locations []file.Location 37 38 if len(coordinates) == 0 { 39 locations = intCataloger.AllRegularFiles(resolver) 40 } else { 41 for _, c := range coordinates { 42 locations = append(locations, file.NewLocationFromCoordinates(c)) 43 } 44 } 45 46 stage, prog := digestsCatalogingProgress(int64(len(locations))) 47 for _, location := range locations { 48 stage.Current = location.RealPath 49 result, err := i.catalogLocation(resolver, location) 50 51 if errors.Is(err, ErrUndigestableFile) { 52 continue 53 } 54 55 if internal.IsErrPathPermission(err) { 56 log.Debugf("file digests cataloger skipping %q: %+v", location.RealPath, err) 57 continue 58 } 59 60 if err != nil { 61 return nil, err 62 } 63 prog.Increment() 64 results[location.Coordinates] = result 65 } 66 log.Debugf("file digests cataloger processed %d files", prog.Current()) 67 prog.SetCompleted() 68 return results, nil 69 } 70 71 func (i *Cataloger) catalogLocation(resolver file.Resolver, location file.Location) ([]file.Digest, error) { 72 meta, err := resolver.FileMetadataByLocation(location) 73 if err != nil { 74 return nil, err 75 } 76 77 // we should only attempt to report digests for files that are regular files (don't attempt to resolve links) 78 if meta.Type != stereoscopeFile.TypeRegular { 79 return nil, ErrUndigestableFile 80 } 81 82 contentReader, err := resolver.FileContentsByLocation(location) 83 if err != nil { 84 return nil, err 85 } 86 defer internal.CloseAndLogError(contentReader, location.AccessPath) 87 88 digests, err := intFile.NewDigestsFromFile(contentReader, i.hashes) 89 if err != nil { 90 return nil, internal.ErrPath{Context: "digests-cataloger", Path: location.RealPath, Err: err} 91 } 92 93 return digests, nil 94 } 95 96 func digestsCatalogingProgress(locations int64) (*progress.Stage, *progress.Manual) { 97 stage := &progress.Stage{} 98 prog := progress.NewManual(locations) 99 100 bus.Publish(partybus.Event{ 101 Type: event.FileDigestsCatalogerStarted, 102 Value: struct { 103 progress.Stager 104 progress.Progressable 105 }{ 106 Stager: progress.Stager(stage), 107 Progressable: prog, 108 }, 109 }) 110 111 return stage, prog 112 }