oci/layout/oci_dest.go
func (d *ociImageDestination) PutBlob(ctx context.Context, stream io.Reader, inputInfo types.BlobInfo, cache types.BlobInfoCache, isConfig bool) (types.BlobInfo, error) {
	blobFile, err := ioutil.TempFile(d.ref.dir, "oci-put-blob")
	if err != nil {
		return types.BlobInfo{}, err
	}
	succeeded := false
	explicitClosed := false
	defer func() {
		if !explicitClosed {
			blobFile.Close()
		}
		if !succeeded {
			os.Remove(blobFile.Name())
		}
	}()

	digester := digest.Canonical.Digester()
	tee := io.TeeReader(stream, digester.Hash())

	// TODO: This can take quite some time, and should ideally be cancellable using ctx.Done().
	size, err := io.Copy(blobFile, tee)
	if err != nil {
		return types.BlobInfo{}, err
	}
	computedDigest := digester.Digest()
	if inputInfo.Size != -1 && size != inputInfo.Size {
		return types.BlobInfo{}, errors.Errorf("Size mismatch when copying %s, expected %d, got %d", computedDigest, inputInfo.Size, size)
	}
	if err := blobFile.Sync(); err != nil {
		return types.BlobInfo{}, err
	}

	// On POSIX systems, blobFile was created with mode 0600, so we need to make it readable.
	// On Windows, the “permissions of newly created files” argument to syscall.Open is
	// ignored and the file is already readable; besides, blobFile.Chmod, i.e. syscall.Fchmod,
	// always fails on Windows.
	if runtime.GOOS != "windows" {
		if err := blobFile.Chmod(0644); err != nil {
			return types.BlobInfo{}, err
		}
	}

	blobPath, err := d.ref.blobPath(computedDigest, d.sharedBlobDir)
	if err != nil {
		return types.BlobInfo{}, err
	}
	if err := ensureParentDirectoryExists(blobPath); err != nil {
		return types.BlobInfo{}, err
	}

	// need to explicitly close the file, since a rename won't otherwise not work on Windows
	blobFile.Close()
	explicitClosed = true
	if err := os.Rename(blobFile.Name(), blobPath); err != nil {
		return types.BlobInfo{}, err
	}
	succeeded = true
	return types.BlobInfo{Digest: computedDigest, Size: size}, nil
}
func (d *ociImageDestination) PutBlob(ctx context.Context, stream io.Reader, inputInfo types.BlobInfo, cache types.BlobInfoCache, isConfig bool) (types.BlobInfo, error) {
	blobFile, err := ioutil.TempFile(d.ref.dir, "oci-put-blob")
	if err != nil {
		return types.BlobInfo{}, err
	}
	succeeded := false
	explicitClosed := false
	defer func() {
		if !explicitClosed {
			blobFile.Close()
		}
		if !succeeded {
			os.Remove(blobFile.Name())
		}
	}()

	digester := digest.Canonical.Digester()
	tee := io.TeeReader(stream, digester.Hash())

	// TODO: This can take quite some time, and should ideally be cancellable using ctx.Done().
	size, err := io.Copy(blobFile, tee)
	if err != nil {
		return types.BlobInfo{}, err
	}
	computedDigest := digester.Digest()
	if inputInfo.Size != -1 && size != inputInfo.Size {
		return types.BlobInfo{}, errors.Errorf("Size mismatch when copying %s, expected %d, got %d", computedDigest, inputInfo.Size, size)
	}
	if err := blobFile.Sync(); err != nil {
		return types.BlobInfo{}, err
	}

	// On POSIX systems, blobFile was created with mode 0600, so we need to make it readable.
	// On Windows, the “permissions of newly created files” argument to syscall.Open is
	// ignored and the file is already readable; besides, blobFile.Chmod, i.e. syscall.Fchmod,
	// always fails on Windows.
	if runtime.GOOS != "windows" {
		if err := blobFile.Chmod(0644); err != nil {
			return types.BlobInfo{}, err
		}
	}

	blobPath, err := d.ref.blobPath(computedDigest, d.sharedBlobDir)
	if err != nil {
		return types.BlobInfo{}, err
	}
	if err := ensureParentDirectoryExists(blobPath); err != nil {
		return types.BlobInfo{}, err
	}

	// need to explicitly close the file, since a rename won't otherwise not work on Windows
	blobFile.Close()
	explicitClosed = true
	if err := os.Rename(blobFile.Name(), blobPath); err != nil {
		return types.BlobInfo{}, err
	}
	succeeded = true
	return types.BlobInfo{Digest: computedDigest, Size: size}, nil
}
func ( d * ociImageDestination ) PutBlob ( ctx context . Context , stream io . Reader , inputInfo types . BlobInfo , cache types . BlobInfoCache , isConfig bool ) ( types . BlobInfo , error ) { blobFile , err := ioutil . TempFile ( d . ref . dir , " " ) if err != nil { return types . BlobInfo { } , err } succeeded := false explicitClosed := false defer func ( ) { if ! explicitClosed { blobFile . Close ( ) } if ! succeeded { os . Remove ( blobFile . Name ( ) ) } } ( ) digester := digest . Canonical . Digester ( ) tee := io . TeeReader ( stream , digester . Hash ( ) ) // TODO: This can take quite some time, and should ideally be cancellable using ctx.Done(). size , err := io . Copy ( blobFile , tee ) if err != nil { return types . BlobInfo { } , err } computedDigest := digester . Digest ( ) if inputInfo . Size != - 1 && size != inputInfo . Size { return types . BlobInfo { } , errors . Errorf ( " " , computedDigest , inputInfo . Size , size ) } if err := blobFile . Sync ( ) ; err != nil { return types . BlobInfo { } , err } // On POSIX systems, blobFile was created with mode 0600, so we need to make it readable. // On Windows, the “permissions of newly created files” argument to syscall.Open is // ignored and the file is already readable; besides, blobFile.Chmod, i.e. syscall.Fchmod, // always fails on Windows. if runtime . GOOS != " " { if err := blobFile . Chmod ( 0644 ) ; err != nil { return types . BlobInfo { } , err } } blobPath , err := d . ref . blobPath ( computedDigest , d . sharedBlobDir ) if err != nil { return types . BlobInfo { } , err } if err := ensureParentDirectoryExists ( blobPath ) ; err != nil { return types . BlobInfo { } , err } // need to explicitly close the file, since a rename won't otherwise not work on Windows blobFile . Close ( ) explicitClosed = true if err := os . Rename ( blobFile . Name ( ) , blobPath ) ; err != nil { return types . BlobInfo { } , err } succeeded = true return types . BlobInfo { Digest : computedDigest , Size : size } , nil }
// PutBlob writes contents of stream and returns data representing the result.
// inputInfo.Digest can be optionally provided if known; it is not mandatory for the implementation to verify it.
// inputInfo.Size is the expected length of stream, if known.
// inputInfo.MediaType describes the blob format, if known.
// May update cache.
// 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.
PutBlob writes contents of stream and returns data representing the result . inputInfo . Digest can be optionally provided if known ; it is not mandatory for the implementation to verify it . inputInfo . Size is the expected length of stream if known . inputInfo . MediaType describes the blob format if known . May update cache . 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 .