Skip to content

Commit

Permalink
ociarchive: Add new ArchiveFileNotFoundError
Browse files Browse the repository at this point in the history
This is for containers/skopeo#2114
which is in turn a dependency of coreos/rpm-ostree#4598

Basically I want to map ENOENT to a clear error, because the build
tooling wants to treat "target image is not present" differently
from "DNS lookup failed" or "we got EPERM".

There's a bit of code motion here because we need to move
the `os.Open()` call before creating a temporary directory.

Signed-off-by: Colin Walters <[email protected]>
  • Loading branch information
cgwalters committed Sep 19, 2023
1 parent 27b3a7e commit 4bec302
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 7 deletions.
12 changes: 12 additions & 0 deletions oci/archive/oci_src.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,18 @@ func (e ImageNotFoundError) Error() string {
return fmt.Sprintf("no descriptor found for reference %q", e.ref.image)
}

// ArchiveFileNotFoundError occurs when the archive file does not exist.
type ArchiveFileNotFoundError struct {
// ref is the image reference
ref ociArchiveReference
// path is the file path that was not present
path string
}

func (e ArchiveFileNotFoundError) Error() string {
return fmt.Sprintf("archive file not found: %q", e.path)
}

type ociArchiveImageSource struct {
impl.Compat

Expand Down
23 changes: 22 additions & 1 deletion oci/archive/oci_src_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
package archive

import "github.com/containers/image/v5/internal/private"
import (
"errors"
"path/filepath"
"testing"

"github.com/containers/image/v5/internal/private"
"github.com/containers/image/v5/types"
"github.com/stretchr/testify/assert"
)

var _ private.ImageSource = (*ociArchiveImageSource)(nil)

func TestNewImageSourceNotFound(t *testing.T) {
emptyDir := t.TempDir()
sysctx := types.SystemContext{BlobInfoCacheDir: emptyDir}
archivePath := filepath.Join(emptyDir, "foo.ociarchive")
imgref, err := ParseReference(archivePath)
assert.Nil(t, err)
_, err = LoadManifestDescriptorWithContext(&sysctx, imgref)
assert.NotNil(t, err)
var aerr ArchiveFileNotFoundError
assert.True(t, errors.As(err, &aerr))
assert.Equal(t, aerr.path, archivePath)
}
19 changes: 13 additions & 6 deletions oci/archive/oci_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"io/fs"
"os"
"strings"

Expand Down Expand Up @@ -171,18 +172,24 @@ func createOCIRef(sys *types.SystemContext, image string) (tempDirOCIRef, error)

// creates the temporary directory and copies the tarred content to it
func createUntarTempDir(sys *types.SystemContext, ref ociArchiveReference) (tempDirOCIRef, error) {
src := ref.resolvedFile
arch, err := os.Open(src)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
return tempDirOCIRef{}, ArchiveFileNotFoundError{ref: ref, path: src}
} else {
return tempDirOCIRef{}, err
}
}
defer arch.Close()

tempDirRef, err := createOCIRef(sys, ref.image)
if err != nil {
return tempDirOCIRef{}, fmt.Errorf("creating oci reference: %w", err)
}
src := ref.resolvedFile
dst := tempDirRef.tempDirectory

// TODO: This can take quite some time, and should ideally be cancellable using a context.Context.
arch, err := os.Open(src)
if err != nil {
return tempDirOCIRef{}, err
}
defer arch.Close()
if err := archive.NewDefaultArchiver().Untar(arch, dst, &archive.TarOptions{NoLchown: true}); err != nil {
if err := tempDirRef.deleteTempDir(); err != nil {
return tempDirOCIRef{}, fmt.Errorf("deleting temp directory %q: %w", tempDirRef.tempDirectory, err)
Expand Down

0 comments on commit 4bec302

Please sign in to comment.