github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/internal/file/zip_file_manifest.go (about) 1 package file 2 3 import ( 4 "fmt" 5 "os" 6 "sort" 7 "strings" 8 9 "github.com/anchore/syft/internal" 10 "github.com/anchore/syft/internal/log" 11 ) 12 13 // ZipFileManifest is a collection of paths and their file metadata. 14 type ZipFileManifest map[string]os.FileInfo 15 16 // NewZipFileManifest creates and returns a new ZipFileManifest populated with path and metadata from the given zip archive path. 17 func NewZipFileManifest(archivePath string) (ZipFileManifest, error) { 18 zipReader, err := OpenZip(archivePath) 19 manifest := make(ZipFileManifest) 20 if err != nil { 21 return manifest, fmt.Errorf("unable to open zip archive (%s): %w", archivePath, err) 22 } 23 defer func() { 24 err = zipReader.Close() 25 if err != nil { 26 log.Warnf("unable to close zip archive (%s): %+v", archivePath, err) 27 } 28 }() 29 30 for _, file := range zipReader.Reader.File { 31 manifest.Add(file.Name, file.FileInfo()) 32 } 33 return manifest, nil 34 } 35 36 // Add a new path and it's file metadata to the collection. 37 func (z ZipFileManifest) Add(entry string, info os.FileInfo) { 38 z[entry] = info 39 } 40 41 // GlobMatch returns the path keys that match the given value(s). 42 func (z ZipFileManifest) GlobMatch(patterns ...string) []string { 43 uniqueMatches := internal.NewStringSet() 44 45 for _, pattern := range patterns { 46 for entry := range z { 47 // We want to match globs as if entries begin with a leading slash (akin to an absolute path) 48 // so that glob logic is consistent inside and outside of ZIP archives 49 normalizedEntry := normalizeZipEntryName(entry) 50 51 if GlobMatch(pattern, normalizedEntry) { 52 uniqueMatches.Add(entry) 53 } 54 } 55 } 56 57 results := uniqueMatches.ToSlice() 58 sort.Strings(results) 59 60 return results 61 } 62 63 // normalizeZipEntryName takes the given path entry and ensures it is prefixed with "/". 64 func normalizeZipEntryName(entry string) string { 65 if !strings.HasPrefix(entry, "/") { 66 return "/" + entry 67 } 68 69 return entry 70 }