| package layer // import "github.com/docker/docker/layer" | |
| import ( | |
| "fmt" | |
| "io" | |
| "github.com/docker/distribution" | |
| "github.com/opencontainers/go-digest" | |
| ) | |
| type roLayer struct { | |
| chainID ChainID | |
| diffID DiffID | |
| parent *roLayer | |
| cacheID string | |
| size int64 | |
| layerStore *layerStore | |
| descriptor distribution.Descriptor | |
| referenceCount int | |
| references map[Layer]struct{} | |
| } | |
| // TarStream for roLayer guarantees that the data that is produced is the exact | |
| // data that the layer was registered with. | |
| func (rl *roLayer) TarStream() (io.ReadCloser, error) { | |
| rc, err := rl.layerStore.getTarStream(rl) | |
| if err != nil { | |
| return nil, err | |
| } | |
| vrc, err := newVerifiedReadCloser(rc, digest.Digest(rl.diffID)) | |
| if err != nil { | |
| return nil, err | |
| } | |
| return vrc, nil | |
| } | |
| // TarStreamFrom does not make any guarantees to the correctness of the produced | |
| // 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) | |
| } | |
| return rl.layerStore.driver.Diff(rl.cacheID, parentCacheID) | |
| } | |
| func (rl *roLayer) CacheID() string { | |
| return rl.cacheID | |
| } | |
| 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() int64 { | |
| size := rl.size | |
| if rl.parent != nil { | |
| size += rl.parent.Size() | |
| } | |
| return size | |
| } | |
| func (rl *roLayer) DiffSize() int64 { | |
| return rl.size | |
| } | |
| func (rl *roLayer) Metadata() (map[string]string, error) { | |
| return rl.layerStore.driver.GetMetadata(rl.cacheID) | |
| } | |
| 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 *fileMetadataTransaction, 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 | |
| } | |
| // Do not store empty descriptors | |
| if layer.descriptor.Digest != "" { | |
| if err := tx.SetDescriptor(layer.descriptor); err != nil { | |
| return err | |
| } | |
| } | |
| if layer.parent != nil { | |
| if err := tx.SetParent(layer.parent.chainID); err != nil { | |
| return err | |
| } | |
| } | |
| return nil | |
| } | |
| func newVerifiedReadCloser(rc io.ReadCloser, dgst digest.Digest) (io.ReadCloser, error) { | |
| return &verifiedReadCloser{ | |
| rc: rc, | |
| dgst: dgst, | |
| verifier: dgst.Verifier(), | |
| }, 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() | |
| } |