layer/ro_layer.go
500e77ba
 package layer
 
50a498ea
 import (
 	"fmt"
 	"io"
 
05bd0435
 	"github.com/docker/distribution"
7a855799
 	"github.com/opencontainers/go-digest"
50a498ea
 )
500e77ba
 
 type roLayer struct {
 	chainID    ChainID
 	diffID     DiffID
 	parent     *roLayer
 	cacheID    string
 	size       int64
 	layerStore *layerStore
2c60430a
 	descriptor distribution.Descriptor
500e77ba
 
 	referenceCount int
 	references     map[Layer]struct{}
 }
 
c8c7a3ff
 // TarStream for roLayer guarantees that the data that is produced is the exact
362369b4
 // data that the layer was registered with.
21278efa
 func (rl *roLayer) TarStream() (io.ReadCloser, error) {
aa96c317
 	rc, err := rl.layerStore.getTarStream(rl)
500e77ba
 	if err != nil {
 		return nil, err
 	}
 
aa96c317
 	vrc, err := newVerifiedReadCloser(rc, digest.Digest(rl.diffID))
50a498ea
 	if err != nil {
 		return nil, err
 	}
aa96c317
 	return vrc, nil
500e77ba
 }
 
c8c7a3ff
 // TarStreamFrom does not make any guarantees to the correctness of the produced
362369b4
 // data. As such it should not be used when the layer content must be verified
 // to be an exact match to the registered layer.
 func (rl *roLayer) TarStreamFrom(parent ChainID) (io.ReadCloser, error) {
 	var parentCacheID string
 	for pl := rl.parent; pl != nil; pl = pl.parent {
 		if pl.chainID == parent {
 			parentCacheID = pl.cacheID
 			break
 		}
 	}
 
 	if parent != ChainID("") && parentCacheID == "" {
 		return nil, fmt.Errorf("layer ID '%s' is not a parent of the specified layer: cannot provide diff to non-parent", parent)
 	}
afd305c4
 	return rl.layerStore.driver.Diff(rl.cacheID, parentCacheID)
362369b4
 }
 
500e77ba
 func (rl *roLayer) ChainID() ChainID {
 	return rl.chainID
 }
 
 func (rl *roLayer) DiffID() DiffID {
 	return rl.diffID
 }
 
 func (rl *roLayer) Parent() Layer {
 	if rl.parent == nil {
 		return nil
 	}
 	return rl.parent
 }
 
 func (rl *roLayer) Size() (size int64, err error) {
 	if rl.parent != nil {
 		size, err = rl.parent.Size()
 		if err != nil {
 			return
 		}
 	}
 
 	return size + rl.size, nil
 }
 
 func (rl *roLayer) DiffSize() (size int64, err error) {
 	return rl.size, nil
 }
 
 func (rl *roLayer) Metadata() (map[string]string, error) {
afd305c4
 	return rl.layerStore.driver.GetMetadata(rl.cacheID)
500e77ba
 }
 
 type referencedCacheLayer struct {
 	*roLayer
 }
 
 func (rl *roLayer) getReference() Layer {
 	ref := &referencedCacheLayer{
 		roLayer: rl,
 	}
 	rl.references[ref] = struct{}{}
 
 	return ref
 }
 
 func (rl *roLayer) hasReference(ref Layer) bool {
 	_, ok := rl.references[ref]
 	return ok
 }
 
 func (rl *roLayer) hasReferences() bool {
 	return len(rl.references) > 0
 }
 
 func (rl *roLayer) deleteReference(ref Layer) {
 	delete(rl.references, ref)
 }
 
 func (rl *roLayer) depth() int {
 	if rl.parent == nil {
 		return 1
 	}
 	return rl.parent.depth() + 1
 }
 
 func storeLayer(tx MetadataTransaction, layer *roLayer) error {
 	if err := tx.SetDiffID(layer.diffID); err != nil {
 		return err
 	}
 	if err := tx.SetSize(layer.size); err != nil {
 		return err
 	}
 	if err := tx.SetCacheID(layer.cacheID); err != nil {
 		return err
 	}
2c60430a
 	// Do not store empty descriptors
 	if layer.descriptor.Digest != "" {
 		if err := tx.SetDescriptor(layer.descriptor); err != nil {
500e77ba
 			return err
 		}
 	}
2c60430a
 	if layer.parent != nil {
 		if err := tx.SetParent(layer.parent.chainID); err != nil {
05bd0435
 			return err
 		}
 	}
0cba7740
 	if err := tx.setOS(layer.layerStore.os); err != nil {
afd305c4
 		return err
 	}
 
 	return nil
500e77ba
 }
50a498ea
 
 func newVerifiedReadCloser(rc io.ReadCloser, dgst digest.Digest) (io.ReadCloser, error) {
 	return &verifiedReadCloser{
 		rc:       rc,
 		dgst:     dgst,
7a855799
 		verifier: dgst.Verifier(),
50a498ea
 	}, nil
 }
 
 type verifiedReadCloser struct {
 	rc       io.ReadCloser
 	dgst     digest.Digest
 	verifier digest.Verifier
 }
 
 func (vrc *verifiedReadCloser) Read(p []byte) (n int, err error) {
 	n, err = vrc.rc.Read(p)
 	if n > 0 {
 		if n, err := vrc.verifier.Write(p[:n]); err != nil {
 			return n, err
 		}
 	}
 	if err == io.EOF {
 		if !vrc.verifier.Verified() {
 			err = fmt.Errorf("could not verify layer data for: %s. This may be because internal files in the layer store were modified. Re-pulling or rebuilding this image may resolve the issue", vrc.dgst)
 		}
 	}
 	return
 }
 func (vrc *verifiedReadCloser) Close() error {
 	return vrc.rc.Close()
 }