github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/internal/file/rpm_file_traversal.go (about) 1 package file 2 3 import ( 4 "io" 5 "os" 6 "path/filepath" 7 8 "github.com/sassoftware/go-rpmutils" 9 ) 10 11 // ExtractGlobsFromRPMToUniqueTempFile extracts paths matching the given globs within the given RPM to a temporary directory, returning file openers for each file extracted. 12 func ExtractGlobsFromRPMToUniqueTempFile(rpmPath, dir string, globs ...string) (map[string]Opener, error) { 13 results := make(map[string]Opener) 14 var err error 15 // don't allow for full traversal, only select traversal from given paths 16 if len(globs) == 0 { 17 return results, nil 18 } 19 f, err := os.Open(rpmPath) 20 if err != nil { 21 return results, nil 22 } 23 defer f.Close() 24 rpm, err := rpmutils.ReadRpm(f) 25 if err != nil { 26 return results, nil 27 } 28 var files int 29 payload, err := rpm.PayloadReaderExtended() 30 if err != nil { 31 return results, nil 32 } 33 for { 34 file, err := payload.Next() 35 if err == io.EOF { 36 break 37 } 38 if !matchesAnyGlob(file.Name(), globs...) { 39 continue 40 } 41 42 // we have a file we want to extract.... 43 tempfilePrefix := filepath.Base(filepath.Clean(file.Name())) + "-" 44 tempFile, err := os.CreateTemp(dir, tempfilePrefix) 45 if err != nil { 46 continue 47 } 48 // we shouldn't try and keep the tempfile open as the returned result may have several files, which takes up 49 // resources (leading to "too many open files"). Instead we'll return a file opener to the caller which 50 // provides a ReadCloser. It is up to the caller to handle closing the file explicitly. 51 if err := safeCopy(tempFile, payload); err != nil { 52 tempFile.Close() 53 continue 54 } 55 results[file.Name()] = Opener{path: tempFile.Name()} 56 tempFile.Close() 57 files++ 58 } 59 60 return results, nil 61 }