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