mirror of
https://github.com/anchore/syft.git
synced 2026-11-01 06:56:40 +01:00
refactoring archive indexing
Signed-off-by: Kudryavcev Nikolay <kydry.nikolau@gmail.com>
This commit is contained in:
@@ -16,8 +16,8 @@ import (
|
|||||||
type archiveAccessPath struct {
|
type archiveAccessPath struct {
|
||||||
realPath string
|
realPath string
|
||||||
accessPath string
|
accessPath string
|
||||||
archiveDepth int
|
|
||||||
archiveRealPath string
|
archiveRealPath string
|
||||||
|
archiveDepth int
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -100,7 +100,11 @@ func (r *Directory) buildIndex() error {
|
|||||||
func (r *Directory) buildArchiveIndex(archiveTempDir string, archives []string, maxArchiveIndexDepth int) error {
|
func (r *Directory) buildArchiveIndex(archiveTempDir string, archives []string, maxArchiveIndexDepth int) error {
|
||||||
archivesToIndex := make([]archiveAccessPath, len(archives))
|
archivesToIndex := make([]archiveAccessPath, len(archives))
|
||||||
for i, archive := range archives {
|
for i, archive := range archives {
|
||||||
archivesToIndex[i] = archiveAccessPath{realPath: archive, accessPath: archive, archiveRealPath: archive}
|
archivesToIndex[i] = archiveAccessPath{
|
||||||
|
realPath: archive,
|
||||||
|
accessPath: archive,
|
||||||
|
archiveRealPath: archive,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
@@ -119,59 +123,59 @@ loop:
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
archivePath, err := os.MkdirTemp(archiveTempDir, archiveContentTempPathPattern)
|
envelopedUnarchiver, err := archiver.ByExtension(currentArchivePath.archiveRealPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not determine archive envelope type: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
unarchiver, ok := envelopedUnarchiver.(archiver.Unarchiver)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unarchiver %T is not an archiver", envelopedUnarchiver)
|
||||||
|
}
|
||||||
|
|
||||||
|
archiveDestinationTempDir, err := os.MkdirTemp(archiveTempDir, archiveContentTempPathPattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to create tempdir for archive processing: %w", err)
|
return fmt.Errorf("unable to create tempdir for archive processing: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
archiveRealPath, err := filepath.EvalSymlinks(archivePath)
|
archiveDestinationPath, err := filepath.EvalSymlinks(archiveDestinationTempDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var pathErr *os.PathError
|
var pathErr *os.PathError
|
||||||
if errors.As(err, &pathErr) {
|
if errors.As(err, &pathErr) {
|
||||||
// we can't index the path, but we shouldn't consider this to be fatal
|
// we can't index the path, but we shouldn't consider this to be fatal
|
||||||
// TODO: known-unknowns
|
// TODO: known-unknowns
|
||||||
log.WithFields("archivePath", archivePath, "error", err).Trace("unable to evaluate symlink while indexing branch")
|
log.WithFields("archivePath", archiveDestinationTempDir, "error", err).Trace("unable to evaluate symlink while indexing branch")
|
||||||
return nil
|
continue
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
envelopedUnarchiver, err := archiver.ByExtension(currentArchivePath.archiveRealPath)
|
if err = unarchiver.Unarchive(currentArchivePath.archiveRealPath, archiveDestinationPath); err != nil {
|
||||||
if err != nil {
|
return fmt.Errorf("unable to unarchive nested file: %w", err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unarchiver, ok := envelopedUnarchiver.(archiver.Unarchiver)
|
d, err := newFromDirectoryWithoutIndex(archiveDestinationPath, "")
|
||||||
if !ok {
|
|
||||||
return ErrSkipPath
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = unarchiver.Unarchive(currentArchivePath.archiveRealPath, archiveRealPath); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
d, err := newFromDirectoryWithoutIndex(archiveRealPath, "")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = d.buildIndex(); err != nil {
|
if err = d.buildIndex(); err != nil {
|
||||||
return err
|
return fmt.Errorf("unable to build index of archive: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, archive := range d.indexer.archivePaths {
|
for _, archive := range d.indexer.archivePaths {
|
||||||
archivesToIndex = append(archivesToIndex, archiveAccessPath{
|
archivesToIndex = append(archivesToIndex, archiveAccessPath{
|
||||||
realPath: currentArchivePath.realPath,
|
realPath: currentArchivePath.realPath,
|
||||||
accessPath: strings.Replace(archive, archiveRealPath, currentArchivePath.accessPath, 1),
|
accessPath: strings.Replace(archive, archiveDestinationPath, currentArchivePath.accessPath, 1),
|
||||||
archiveDepth: currentArchivePath.archiveDepth + 1,
|
|
||||||
archiveRealPath: archive,
|
archiveRealPath: archive,
|
||||||
|
archiveDepth: currentArchivePath.archiveDepth + 1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
d.chroot = r.chroot
|
d.chroot = r.chroot
|
||||||
d.realPath = currentArchivePath.realPath
|
d.realPath = currentArchivePath.realPath
|
||||||
d.accessPath = currentArchivePath.accessPath
|
d.accessPath = currentArchivePath.accessPath
|
||||||
d.tempDir = archiveRealPath
|
d.archiveRealPath = archiveDestinationPath
|
||||||
|
|
||||||
r.archives = append(r.archives, &d.filetreeResolver)
|
r.archives = append(r.archives, &d.filetreeResolver)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ type filetreeResolver struct {
|
|||||||
index filetree.IndexReader
|
index filetree.IndexReader
|
||||||
searchContext filetree.Searcher
|
searchContext filetree.Searcher
|
||||||
|
|
||||||
realPath string
|
realPath string
|
||||||
accessPath string
|
accessPath string
|
||||||
tempDir string
|
archiveRealPath string
|
||||||
archives []*filetreeResolver
|
archives []*filetreeResolver
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *filetreeResolver) requestPath(userPath string) (string, error) {
|
func (r *filetreeResolver) requestPath(userPath string) (string, error) {
|
||||||
@@ -33,8 +33,8 @@ func (r *filetreeResolver) requestPath(userPath string) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.accessPath != "" && r.tempDir != "" {
|
if r.accessPath != "" && r.archiveRealPath != "" {
|
||||||
return strings.Replace(requestPath, r.accessPath, r.tempDir, 1), nil
|
return strings.Replace(requestPath, r.accessPath, r.archiveRealPath, 1), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return requestPath, nil
|
return requestPath, nil
|
||||||
@@ -42,15 +42,19 @@ func (r *filetreeResolver) requestPath(userPath string) (string, error) {
|
|||||||
|
|
||||||
// responsePath takes a path from the underlying fs domain and converts it to a path that is relative to the root of the file resolver.
|
// responsePath takes a path from the underlying fs domain and converts it to a path that is relative to the root of the file resolver.
|
||||||
func (r filetreeResolver) responsePath(path string) string {
|
func (r filetreeResolver) responsePath(path string) string {
|
||||||
if r.tempDir != "" && strings.HasPrefix(path, r.tempDir) {
|
if r.archiveRealPath != "" && strings.HasPrefix(path, r.archiveRealPath) {
|
||||||
path = r.realPath
|
path = r.realPath
|
||||||
}
|
}
|
||||||
|
|
||||||
return r.chroot.ToChrootPath(path)
|
return r.chroot.ToChrootPath(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r filetreeResolver) responseAccessPath(path string) string {
|
func (r filetreeResolver) responseAccessPath(path string) string {
|
||||||
responsePath := strings.Replace(path, r.tempDir, r.accessPath, 1)
|
if r.accessPath != "" && r.archiveRealPath != "" {
|
||||||
return r.chroot.ToChrootPath(responsePath)
|
path = strings.Replace(path, r.archiveRealPath, r.accessPath, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.chroot.ToChrootPath(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasPath indicates if the given path exists in the underlying source.
|
// HasPath indicates if the given path exists in the underlying source.
|
||||||
@@ -138,7 +142,11 @@ func (r filetreeResolver) requestGlob(pattern string) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Replace(nativeGlob, r.accessPath, r.tempDir, 1), nil
|
if r.accessPath != "" && r.archiveRealPath != "" {
|
||||||
|
return strings.Replace(nativeGlob, r.accessPath, r.archiveRealPath, 1), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nativeGlob, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilesByGlob returns all file.References that match the given path glob pattern from any layer in the image.
|
// FilesByGlob returns all file.References that match the given path glob pattern from any layer in the image.
|
||||||
|
|||||||
@@ -1664,6 +1664,7 @@ func TestFileResolver_AllLocations_errorOnDirRequest(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileResolver_AllLocations(t *testing.T) {
|
func TestFileResolver_AllLocations(t *testing.T) {
|
||||||
|
defer goleak.VerifyNone(t)
|
||||||
// Verify both the parent and the file itself are indexed
|
// Verify both the parent and the file itself are indexed
|
||||||
filePath := "./test-fixtures/system_paths/target/home/place"
|
filePath := "./test-fixtures/system_paths/target/home/place"
|
||||||
parentPath, err := absoluteSymlinkFreePathToParent(filePath)
|
parentPath, err := absoluteSymlinkFreePathToParent(filePath)
|
||||||
@@ -1685,11 +1686,10 @@ func TestFileResolver_AllLocations(t *testing.T) {
|
|||||||
sort.Strings(pathsList)
|
sort.Strings(pathsList)
|
||||||
|
|
||||||
assert.ElementsMatchf(t, expected, pathsList, "expected all paths to be indexed, but found different paths: \n%s", cmp.Diff(expected, paths.List()))
|
assert.ElementsMatchf(t, expected, pathsList, "expected all paths to be indexed, but found different paths: \n%s", cmp.Diff(expected, paths.List()))
|
||||||
|
|
||||||
goleak.VerifyNone(t)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_FileResolver_AllLocationsDoesNotLeakGoRoutine(t *testing.T) {
|
func Test_FileResolver_AllLocationsDoesNotLeakGoRoutine(t *testing.T) {
|
||||||
|
defer goleak.VerifyNone(t)
|
||||||
filePath := "./test-fixtures/system_paths/target/home/place"
|
filePath := "./test-fixtures/system_paths/target/home/place"
|
||||||
parentPath, err := absoluteSymlinkFreePathToParent(filePath)
|
parentPath, err := absoluteSymlinkFreePathToParent(filePath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -1703,6 +1703,4 @@ func Test_FileResolver_AllLocationsDoesNotLeakGoRoutine(t *testing.T) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
cancel()
|
cancel()
|
||||||
|
|
||||||
goleak.VerifyNone(t)
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user