Files
syft/internal/archive/workdir.go
T
2026-09-22 00:23:36 -04:00

72 lines
1.9 KiB
Go

package archive
import (
"context"
"fmt"
"os"
"github.com/anchore/syft/internal/log"
"github.com/anchore/syft/internal/tmpdir"
)
// workDirName prefixes the directory holding one archive's overflow files.
const workDirName = "syft-archive"
// WorkDir is the scratch directory one archive writes overflow into. It is created on first use, so
// an archive that stays in memory never touches the filesystem.
type WorkDir struct {
tempDir *tmpdir.TempDir
created bool
path string
remove func()
err error
}
// NewWorkDir returns a work directory under the scan's temp root when ctx carries one (see
// internal/tmpdir), otherwise under the system temp directory.
func NewWorkDir(ctx context.Context) *WorkDir {
return &WorkDir{tempDir: tmpdir.FromContext(ctx)}
}
// Path returns the directory, creating it on the first call.
func (w *WorkDir) Path() (string, error) {
if w == nil {
return "", fmt.Errorf("no work directory for archive content")
}
if !w.created {
w.created = true
w.path, w.remove, w.err = w.create()
}
return w.path, w.err
}
func (w *WorkDir) create() (string, func(), error) {
if w.tempDir != nil {
dir, remove, err := w.tempDir.NewChild(workDirName) //nolint:gocritic // the cleanup is returned, not deferred
if err != nil {
return "", nil, fmt.Errorf("unable to create temp dir for archive extraction: %w", err)
}
return dir, remove, nil
}
dir, err := os.MkdirTemp("", workDirName+"-")
if err != nil {
return "", nil, fmt.Errorf("unable to create temp dir for archive extraction: %w", err)
}
return dir, func() {
if err := os.RemoveAll(dir); err != nil {
log.WithFields("dir", dir, "error", err).Trace("unable to remove archive temp dir")
}
}, nil
}
// Remove deletes the directory if it was created. Safe to call more than once.
func (w *WorkDir) Remove() {
if w == nil || w.remove == nil {
return
}
w.remove()
w.remove = nil
}