1package layer // import "github.com/docker/docker/layer"
2
3import (
4	"io"
5	"sync"
6
7	"github.com/docker/docker/pkg/archive"
8	"github.com/docker/docker/pkg/containerfs"
9)
10
11type mountedLayer struct {
12	name       string
13	mountID    string
14	initID     string
15	parent     *roLayer
16	layerStore *layerStore
17
18	sync.Mutex
19	references map[RWLayer]*referencedRWLayer
20}
21
22func (ml *mountedLayer) cacheParent() string {
23	if ml.initID != "" {
24		return ml.initID
25	}
26	if ml.parent != nil {
27		return ml.parent.cacheID
28	}
29	return ""
30}
31
32func (ml *mountedLayer) TarStream() (io.ReadCloser, error) {
33	return ml.layerStore.driver.Diff(ml.mountID, ml.cacheParent())
34}
35
36func (ml *mountedLayer) Name() string {
37	return ml.name
38}
39
40func (ml *mountedLayer) Parent() Layer {
41	if ml.parent != nil {
42		return ml.parent
43	}
44
45	// Return a nil interface instead of an interface wrapping a nil
46	// pointer.
47	return nil
48}
49
50func (ml *mountedLayer) Size() (int64, error) {
51	return ml.layerStore.driver.DiffSize(ml.mountID, ml.cacheParent())
52}
53
54func (ml *mountedLayer) Changes() ([]archive.Change, error) {
55	return ml.layerStore.driver.Changes(ml.mountID, ml.cacheParent())
56}
57
58func (ml *mountedLayer) Metadata() (map[string]string, error) {
59	return ml.layerStore.driver.GetMetadata(ml.mountID)
60}
61
62func (ml *mountedLayer) getReference() RWLayer {
63	ref := &referencedRWLayer{
64		mountedLayer: ml,
65	}
66	ml.Lock()
67	ml.references[ref] = ref
68	ml.Unlock()
69
70	return ref
71}
72
73func (ml *mountedLayer) hasReferences() bool {
74	ml.Lock()
75	ret := len(ml.references) > 0
76	ml.Unlock()
77
78	return ret
79}
80
81func (ml *mountedLayer) deleteReference(ref RWLayer) error {
82	ml.Lock()
83	defer ml.Unlock()
84	if _, ok := ml.references[ref]; !ok {
85		return ErrLayerNotRetained
86	}
87	delete(ml.references, ref)
88	return nil
89}
90
91func (ml *mountedLayer) retakeReference(r RWLayer) {
92	if ref, ok := r.(*referencedRWLayer); ok {
93		ml.Lock()
94		ml.references[ref] = ref
95		ml.Unlock()
96	}
97}
98
99type referencedRWLayer struct {
100	*mountedLayer
101}
102
103func (rl *referencedRWLayer) Mount(mountLabel string) (containerfs.ContainerFS, error) {
104	return rl.layerStore.driver.Get(rl.mountedLayer.mountID, mountLabel)
105}
106
107// Unmount decrements the activity count and unmounts the underlying layer
108// Callers should only call `Unmount` once per call to `Mount`, even on error.
109func (rl *referencedRWLayer) Unmount() error {
110	return rl.layerStore.driver.Put(rl.mountedLayer.mountID)
111}
112
113// ApplyDiff applies specified diff to the layer
114func (rl *referencedRWLayer) ApplyDiff(diff io.Reader) (int64, error) {
115	return rl.layerStore.driver.ApplyDiff(rl.mountID, rl.cacheParent(), diff)
116}
117