Skip to content

Commit

Permalink
fix(libindex): temp files on non-linux
Browse files Browse the repository at this point in the history
Signed-off-by: RTann <rtannenb@redhat.com>
  • Loading branch information
RTann committed Nov 13, 2023
1 parent aad7b14 commit 9fbdd6e
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 15 deletions.
20 changes: 5 additions & 15 deletions libindex/fetcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"io"
"net/http"
"net/url"
"os"
"runtime"
"strings"
"sync"
Expand All @@ -21,7 +20,6 @@ import (
"go.opentelemetry.io/otel/trace"
"golang.org/x/sync/errgroup"
"golang.org/x/sync/singleflight"
"golang.org/x/sys/unix"

"github.com/quay/claircore"
"github.com/quay/claircore/indexer"
Expand Down Expand Up @@ -66,13 +64,13 @@ func NewRemoteFetchArena(wc *http.Client, root string) *RemoteFetchArena {
// Rc is a reference counter.
type rc struct {
sync.Mutex
val *os.File
val *tempFile
count int
done func()
}

// NewRc makes an rc.
func newRc(v *os.File, done func()) *rc {
func newRc(v *tempFile, done func()) *rc {
return &rc{
val: v,
done: done,
Expand Down Expand Up @@ -112,18 +110,10 @@ type ref struct {
}

// Val clones the inner File.
func (r *ref) Val() (*os.File, error) {
func (r *ref) Val() (*tempFile, error) {
r.rc.Lock()
defer r.rc.Unlock()
fd := int(r.rc.val.Fd())
if fd == -1 {
return nil, errStale
}
p := fmt.Sprintf(`/proc/self/fd/%d`, fd)
// Need to use OpenFile so that the symlink is not dereferenced.
// There's some proc magic so that opening that symlink itself copies the
// description.
return os.OpenFile(p, os.O_RDONLY, 0644)
return r.rc.val.read()
}

// Close decrements the refcount.
Expand Down Expand Up @@ -250,7 +240,7 @@ func (a *RemoteFetchArena) fetchUnlinkedFile(ctx context.Context, key string, de
return v.(*rc), nil
}
// Otherwise, it needs to be populated.
f, err := os.OpenFile(a.root, os.O_WRONLY|unix.O_TMPFILE, 0644)
f, err := openTemp(a.root)
if err != nil {
return nil, err
}
Expand Down
37 changes: 37 additions & 0 deletions libindex/tempfile_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package libindex

import (
"fmt"
"os"

"golang.org/x/sys/unix"
)

type tempFile struct {
*os.File
}

func openTemp(dir string) (*tempFile, error) {
f, err := os.OpenFile(dir, os.O_WRONLY|unix.O_TMPFILE, 0644)
if err != nil {
return nil, err
}

Check warning on line 18 in libindex/tempfile_linux.go

View check run for this annotation

Codecov / codecov/patch

libindex/tempfile_linux.go#L17-L18

Added lines #L17 - L18 were not covered by tests
return &tempFile{
File: f,
}, nil
}

func (t *tempFile) read() (*tempFile, error) {
fd := int(t.Fd())
if fd == -1 {
return nil, errStale
}
p := fmt.Sprintf("/proc/self/fd/%d", fd)
f, err := os.OpenFile(p, os.O_RDONLY, 0644)
if err != nil {
return nil, err
}

Check warning on line 33 in libindex/tempfile_linux.go

View check run for this annotation

Codecov / codecov/patch

libindex/tempfile_linux.go#L32-L33

Added lines #L32 - L33 were not covered by tests
return &tempFile{
File: f,
}, nil
}
40 changes: 40 additions & 0 deletions libindex/tempfile_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//go:build unix && !linux

package libindex

import "os"

type tempFile struct {
*os.File
removeOnClose bool
}

func openTemp(dir string) (*tempFile, error) {
f, err := os.CreateTemp(dir, "*.fetch")
if err != nil {
return nil, err
}
return &tempFile{
File: f,
removeOnClose: true,
}, nil
}

func (t *tempFile) read() (*tempFile, error) {
f, err := os.OpenFile(t.Name(), os.O_RDONLY, 0644)
if err != nil {
return nil, err
}
return &tempFile{
File: f,
}, nil
}

func (t *tempFile) Close() error {
if t.removeOnClose {
if err := os.Remove(t.Name()); err != nil {
return err
}
}
return t.File.Close()
}
49 changes: 49 additions & 0 deletions libindex/tempfile_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package libindex

import (
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
_ "unsafe" // linker tricks
)

// This is a very rough port of src/os/tempfile.go that adds the magic
// autodelete flag.

//go:linkname fastrand runtime.fastrand
func fastrand() uint32

type tempFile struct {
*os.File
}

func openTemp(dir string) (*tempFile, error) {
// Copied out of golang.org/x/sys/windows
const FILE_FLAG_DELETE_ON_CLOSE = 0x04000000
for {
fn := fmt.Sprintf("fetch.%d", fastrand())
f, err := os.OpenFile(filepath.Join(dir, fn), os.O_WRONLY|FILE_FLAG_DELETE_ON_CLOSE, 0644)
switch {
case errors.Is(err, nil):
return &tempFile{
File: f,
}, nil
case errors.Is(err, fs.ErrExist):
// Continue
default:
return nil, err
}
}
}

func (t *tempFile) read() (*tempFile, error) {
f, err := os.OpenFile(t.Name(), os.O_RDONLY, 0644)
if err != nil {
return nil, err
}
return &tempFile{
File: f,
}, nil
}

0 comments on commit 9fbdd6e

Please sign in to comment.