From 6e2cd739da4fd4c4834f35d21c5e26e378f75212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Thu, 4 Aug 2016 19:27:28 +0200 Subject: [PATCH] Vendor after merging mtrmac/image:PutBlob-error-handling --- .../image/directory/directory_dest.go | 29 ++++++++++++++++--- .../image/directory/directory_transport.go | 6 +++- .../image/docker/docker_image_dest.go | 5 ++++ .../containers/image/oci/oci_dest.go | 27 ++++++++++++++--- .../containers/image/oci/oci_transport.go | 4 +++ .../containers/image/openshift/openshift.go | 5 ++++ .../containers/image/types/types.go | 4 +++ 7 files changed, 71 insertions(+), 9 deletions(-) diff --git a/vendor/github.com/containers/image/directory/directory_dest.go b/vendor/github.com/containers/image/directory/directory_dest.go index 9cee862a..fb5ff757 100644 --- a/vendor/github.com/containers/image/directory/directory_dest.go +++ b/vendor/github.com/containers/image/directory/directory_dest.go @@ -4,6 +4,7 @@ import ( "io" "io/ioutil" "os" + "path/filepath" "github.com/containers/image/types" ) @@ -31,18 +32,38 @@ func (d *dirImageDestination) PutManifest(manifest []byte) error { return ioutil.WriteFile(d.ref.manifestPath(), manifest, 0644) } +// PutBlob writes contents of stream as a blob identified by digest. +// WARNING: The contents of stream are being verified on the fly. Until stream.Read() returns io.EOF, the contents of the data SHOULD NOT be available +// to any other readers for download using the supplied digest. +// If stream.Read() at any time, ESPECIALLY at end of input, returns an error, PutBlob MUST 1) fail, and 2) delete any data stored so far. +// Note: Calling PutBlob() and other methods may have ordering dependencies WRT other methods of this type. FIXME: Figure out and document. func (d *dirImageDestination) PutBlob(digest string, stream io.Reader) error { - layerFile, err := os.Create(d.ref.layerPath(digest)) + blobPath := d.ref.layerPath(digest) + blobFile, err := ioutil.TempFile(filepath.Dir(blobPath), filepath.Base(blobPath)) if err != nil { return err } - defer layerFile.Close() - if _, err := io.Copy(layerFile, stream); err != nil { + succeeded := false + defer func() { + blobFile.Close() + if !succeeded { + os.Remove(blobFile.Name()) + } + }() + + if _, err := io.Copy(blobFile, stream); err != nil { return err } - if err := layerFile.Sync(); err != nil { + if err := blobFile.Sync(); err != nil { return err } + if err := blobFile.Chmod(0644); err != nil { + return err + } + if err := os.Rename(blobFile.Name(), blobPath); err != nil { + return nil + } + succeeded = true return nil } diff --git a/vendor/github.com/containers/image/directory/directory_transport.go b/vendor/github.com/containers/image/directory/directory_transport.go index a6b7bed0..c5547f7c 100644 --- a/vendor/github.com/containers/image/directory/directory_transport.go +++ b/vendor/github.com/containers/image/directory/directory_transport.go @@ -32,13 +32,17 @@ func (t dirTransport) ParseReference(reference string) (types.ImageReference, er // scope passed to this function will not be "", that value is always allowed. func (t dirTransport) ValidatePolicyConfigurationScope(scope string) error { if !strings.HasPrefix(scope, "/") { - return fmt.Errorf("Invalid scope %s: must be an absolute path", scope) + return fmt.Errorf("Invalid scope %s: Must be an absolute path", scope) } // Refuse also "/", otherwise "/" and "" would have the same semantics, // and "" could be unexpectedly shadowed by the "/" entry. if scope == "/" { return errors.New(`Invalid scope "/": Use the generic default scope ""`) } + cleaned := filepath.Clean(scope) + if cleaned != scope { + return fmt.Errorf(`Invalid scope %s: Uses non-canonical format, perhaps try %s`, scope, cleaned) + } return nil } diff --git a/vendor/github.com/containers/image/docker/docker_image_dest.go b/vendor/github.com/containers/image/docker/docker_image_dest.go index 818c8409..86a38e64 100644 --- a/vendor/github.com/containers/image/docker/docker_image_dest.go +++ b/vendor/github.com/containers/image/docker/docker_image_dest.go @@ -74,6 +74,11 @@ func (d *dockerImageDestination) PutManifest(m []byte) error { return nil } +// PutBlob writes contents of stream as a blob identified by digest. +// WARNING: The contents of stream are being verified on the fly. Until stream.Read() returns io.EOF, the contents of the data SHOULD NOT be available +// to any other readers for download using the supplied digest. +// If stream.Read() at any time, ESPECIALLY at end of input, returns an error, PutBlob MUST 1) fail, and 2) delete any data stored so far. +// Note: Calling PutBlob() and other methods may have ordering dependencies WRT other methods of this type. FIXME: Figure out and document. func (d *dockerImageDestination) PutBlob(digest string, stream io.Reader) error { checkURL := fmt.Sprintf(blobsURL, d.ref.ref.RemoteName(), digest) diff --git a/vendor/github.com/containers/image/oci/oci_dest.go b/vendor/github.com/containers/image/oci/oci_dest.go index 6509aba2..163d5004 100644 --- a/vendor/github.com/containers/image/oci/oci_dest.go +++ b/vendor/github.com/containers/image/oci/oci_dest.go @@ -110,22 +110,41 @@ func (d *ociImageDestination) PutManifest(m []byte) error { return ioutil.WriteFile(descriptorPath, data, 0644) } +// PutBlob writes contents of stream as a blob identified by digest. +// WARNING: The contents of stream are being verified on the fly. Until stream.Read() returns io.EOF, the contents of the data SHOULD NOT be available +// to any other readers for download using the supplied digest. +// If stream.Read() at any time, ESPECIALLY at end of input, returns an error, PutBlob MUST 1) fail, and 2) delete any data stored so far. +// Note: Calling PutBlob() and other methods may have ordering dependencies WRT other methods of this type. FIXME: Figure out and document. func (d *ociImageDestination) PutBlob(digest string, stream io.Reader) error { blobPath := d.ref.blobPath(digest) if err := ensureParentDirectoryExists(blobPath); err != nil { return err } - blob, err := os.Create(blobPath) + blobFile, err := ioutil.TempFile(filepath.Dir(blobPath), filepath.Base(blobPath)) if err != nil { return err } - defer blob.Close() - if _, err := io.Copy(blob, stream); err != nil { + succeeded := false + defer func() { + blobFile.Close() + if !succeeded { + os.Remove(blobFile.Name()) + } + }() + + if _, err := io.Copy(blobFile, stream); err != nil { return err } - if err := blob.Sync(); err != nil { + if err := blobFile.Sync(); err != nil { return err } + if err := blobFile.Chmod(0644); err != nil { + return err + } + if err := os.Rename(blobFile.Name(), blobPath); err != nil { + return nil + } + succeeded = true return nil } diff --git a/vendor/github.com/containers/image/oci/oci_transport.go b/vendor/github.com/containers/image/oci/oci_transport.go index 1ec28f57..f3afd221 100644 --- a/vendor/github.com/containers/image/oci/oci_transport.go +++ b/vendor/github.com/containers/image/oci/oci_transport.go @@ -58,6 +58,10 @@ func (t ociTransport) ValidatePolicyConfigurationScope(scope string) error { if scope == "/" { return errors.New(`Invalid scope "/": Use the generic default scope ""`) } + cleaned := filepath.Clean(dir) + if cleaned != dir { + return fmt.Errorf(`Invalid scope %s: Uses non-canonical path format, perhaps try with path %s`, scope, cleaned) + } return nil } diff --git a/vendor/github.com/containers/image/openshift/openshift.go b/vendor/github.com/containers/image/openshift/openshift.go index 659f4783..17ae5c43 100644 --- a/vendor/github.com/containers/image/openshift/openshift.go +++ b/vendor/github.com/containers/image/openshift/openshift.go @@ -368,6 +368,11 @@ func (d *openshiftImageDestination) PutManifest(m []byte) error { return nil } +// PutBlob writes contents of stream as a blob identified by digest. +// WARNING: The contents of stream are being verified on the fly. Until stream.Read() returns io.EOF, the contents of the data SHOULD NOT be available +// to any other readers for download using the supplied digest. +// If stream.Read() at any time, ESPECIALLY at end of input, returns an error, PutBlob MUST 1) fail, and 2) delete any data stored so far. +// Note: Calling PutBlob() and other methods may have ordering dependencies WRT other methods of this type. FIXME: Figure out and document. func (d *openshiftImageDestination) PutBlob(digest string, stream io.Reader) error { return d.docker.PutBlob(digest, stream) } diff --git a/vendor/github.com/containers/image/types/types.go b/vendor/github.com/containers/image/types/types.go index 086e0080..b67e6b30 100644 --- a/vendor/github.com/containers/image/types/types.go +++ b/vendor/github.com/containers/image/types/types.go @@ -104,6 +104,10 @@ type ImageDestination interface { Reference() ImageReference // FIXME? This should also receive a MIME type if known, to differentiate between schema versions. PutManifest([]byte) error + // PutBlob writes contents of stream as a blob identified by digest. + // WARNING: The contents of stream are being verified on the fly. Until stream.Read() returns io.EOF, the contents of the data SHOULD NOT be available + // to any other readers for download using the supplied digest. + // If stream.Read() at any time, ESPECIALLY at end of input, returns an error, PutBlob MUST 1) fail, and 2) delete any data stored so far. // Note: Calling PutBlob() and other methods may have ordering dependencies WRT other methods of this type. FIXME: Figure out and document. PutBlob(digest string, stream io.Reader) error PutSignatures(signatures [][]byte) error