mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-05 20:40:16 -08:00
Signed-off-by: knqyf263 <knqyf263@gmail.com> Co-authored-by: knqyf263 <knqyf263@users.noreply.github.com>
84 lines
2.0 KiB
Go
84 lines
2.0 KiB
Go
package walker
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"os"
|
|
"sync"
|
|
|
|
"golang.org/x/xerrors"
|
|
|
|
xio "github.com/aquasecurity/trivy/pkg/x/io"
|
|
xos "github.com/aquasecurity/trivy/pkg/x/os"
|
|
)
|
|
|
|
// cachedFile represents a file cached in memory or storage according to the file size.
|
|
type cachedFile struct {
|
|
once sync.Once
|
|
err error
|
|
|
|
size int64
|
|
reader io.Reader
|
|
|
|
content []byte // It will be populated if this file is small
|
|
filePath string // It will be populated if this file is large
|
|
}
|
|
|
|
func newCachedFile(size int64, r io.Reader) *cachedFile {
|
|
return &cachedFile{
|
|
size: size,
|
|
reader: r,
|
|
}
|
|
}
|
|
|
|
// Open opens a file and cache the file.
|
|
// If the file size is greater than or equal to threshold, it copies the content to a temp file and opens it next time.
|
|
// If the file size is less than threshold, it opens the file once and the content will be shared so that others analyzers can use the same data.
|
|
func (o *cachedFile) Open() (xio.ReadSeekCloserAt, error) {
|
|
o.once.Do(func() {
|
|
// When the file is large, it will be written down to a temp file.
|
|
if o.size >= defaultSizeThreshold {
|
|
f, err := xos.CreateTemp("", "cached-file-")
|
|
if err != nil {
|
|
o.err = xerrors.Errorf("failed to create the temp file: %w", err)
|
|
return
|
|
}
|
|
|
|
if _, err = io.Copy(f, o.reader); err != nil {
|
|
o.err = xerrors.Errorf("failed to copy: %w", err)
|
|
return
|
|
}
|
|
|
|
o.filePath = f.Name()
|
|
} else {
|
|
b, err := io.ReadAll(o.reader)
|
|
if err != nil {
|
|
o.err = xerrors.Errorf("unable to read the file: %w", err)
|
|
return
|
|
}
|
|
o.content = b
|
|
}
|
|
})
|
|
if o.err != nil {
|
|
return nil, xerrors.Errorf("failed to open: %w", o.err)
|
|
}
|
|
|
|
return o.open()
|
|
}
|
|
|
|
func (o *cachedFile) open() (xio.ReadSeekCloserAt, error) {
|
|
if o.filePath != "" {
|
|
f, err := os.Open(o.filePath)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("failed to open the temp file: %w", err)
|
|
}
|
|
return f, nil
|
|
}
|
|
|
|
return xio.NopCloser(bytes.NewReader(o.content)), nil
|
|
}
|
|
|
|
func (o *cachedFile) Clean() error {
|
|
return os.Remove(o.filePath)
|
|
}
|