github.com/quay/claircore@v1.5.28/libindex/tempfile_linux.go (about)

     1  package libindex
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"sync"
     8  
     9  	"golang.org/x/sys/unix"
    10  )
    11  
    12  var tmpMap sync.Map
    13  
    14  func canTmp(dir string) (ok, loaded bool) {
    15  	v, loaded := tmpMap.Load(dir)
    16  	if v == nil {
    17  		return false, loaded
    18  	}
    19  	return v.(bool), loaded
    20  }
    21  
    22  func setTmp(dir string, ok bool) {
    23  	tmpMap.Store(dir, ok)
    24  }
    25  
    26  type tempFile struct {
    27  	*os.File
    28  }
    29  
    30  func openTemp(dir string) (*tempFile, error) {
    31  	var f *os.File
    32  	var err error
    33  
    34  	ok, loaded := canTmp(dir)
    35  	switch {
    36  	case loaded && ok:
    37  		f, err = os.OpenFile(dir, os.O_WRONLY|unix.O_TMPFILE, 0644)
    38  	case loaded && !ok:
    39  		f, err = os.CreateTemp(dir, "fetcher.*")
    40  	case !loaded:
    41  		f, err = os.OpenFile(dir, os.O_WRONLY|unix.O_TMPFILE, 0644)
    42  		if err == nil || !errors.Is(err, unix.ENOTSUP) {
    43  			ok = true
    44  			break
    45  		}
    46  		f, err = os.CreateTemp(dir, "fetcher.*")
    47  	default:
    48  		panic("unreachable")
    49  	}
    50  	if !loaded {
    51  		setTmp(dir, ok)
    52  	}
    53  	if !ok && err == nil {
    54  		// This is just a best-effort action to keep files from accumulating.
    55  		// The correct way is to use the kernel feature for this: the O_TMPFILE flag.
    56  		_ = os.Remove(f.Name())
    57  	}
    58  
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	return &tempFile{File: f}, nil
    63  }
    64  
    65  func (t *tempFile) Reopen() (*os.File, error) {
    66  	fd := int(t.Fd())
    67  	if fd == -1 {
    68  		return nil, errStale
    69  	}
    70  	p := fmt.Sprintf("/proc/self/fd/%d", fd)
    71  	// Need to use OpenFile so that the symlink is not dereferenced.
    72  	// There's some proc magic so that opening that symlink itself copies the
    73  	// description.
    74  	return os.OpenFile(p, os.O_RDONLY, 0644)
    75  }