Add ability to scan snaps (as a source) (#3929)

This commit is contained in:
Alex Goodman
2025-06-25 16:53:35 -04:00
committed by GitHub
parent 4eb8ba4575
commit 2bda086423
63 changed files with 5060 additions and 175 deletions
+67 -6
View File
@@ -4,6 +4,9 @@ import (
"bytes"
"fmt"
"io"
"sync"
"github.com/diskfs/go-diskfs/filesystem/squashfs"
macho "github.com/anchore/go-macholibre"
"github.com/anchore/syft/internal/log"
@@ -48,12 +51,15 @@ func GetUnionReader(readerCloser io.ReadCloser) (UnionReader, error) {
// file.LocationReadCloser embeds a ReadCloser, which is likely
// to implement UnionReader. Check whether the embedded read closer
// implements UnionReader, and just return that if so.
r, ok := readerCloser.(file.LocationReadCloser)
if ok {
ur, ok := r.ReadCloser.(UnionReader)
if ok {
return ur, nil
}
if r, ok := readerCloser.(file.LocationReadCloser); ok {
return GetUnionReader(r.ReadCloser)
}
if r, ok := readerCloser.(*squashfs.File); ok {
// seeking is implemented, but not io.ReaderAt. Lets wrap it to prevent from degrading performance
// by copying all data.
return newReaderAtAdapter(r), nil
}
b, err := io.ReadAll(readerCloser)
@@ -75,3 +81,58 @@ func GetUnionReader(readerCloser io.ReadCloser) (UnionReader, error) {
return reader, nil
}
type readerAtAdapter struct {
io.ReadSeekCloser
mu *sync.Mutex
}
func newReaderAtAdapter(rs io.ReadSeekCloser) UnionReader {
return &readerAtAdapter{
ReadSeekCloser: rs,
mu: &sync.Mutex{},
}
}
func (r *readerAtAdapter) Read(p []byte) (n int, err error) {
r.mu.Lock()
defer r.mu.Unlock()
return r.ReadSeekCloser.Read(p)
}
func (r *readerAtAdapter) Seek(offset int64, whence int) (int64, error) {
r.mu.Lock()
defer r.mu.Unlock()
return r.ReadSeekCloser.Seek(offset, whence)
}
func (r *readerAtAdapter) ReadAt(p []byte, off int64) (n int, err error) {
r.mu.Lock()
defer r.mu.Unlock()
currentPos, err := r.ReadSeekCloser.Seek(0, io.SeekCurrent) // save current pos
if err != nil {
return 0, err
}
_, err = r.ReadSeekCloser.Seek(off, io.SeekStart) // seek to absolute position `off`
if err != nil {
return 0, err
}
n, err = r.ReadSeekCloser.Read(p) // read from that absolute position
// restore the position for the stateful read/seek operations
if restoreErr := r.restorePosition(currentPos); restoreErr != nil {
if err == nil {
err = restoreErr
}
}
return n, err
}
func (r *readerAtAdapter) restorePosition(pos int64) error {
_, err := r.ReadSeekCloser.Seek(pos, io.SeekStart)
return err
}