Skip to content
This repository was archived by the owner on Mar 9, 2022. It is now read-only.

Commit 63f2737

Browse files
committed
Support symlink layer in image import.
Signed-off-by: Lantao Liu <[email protected]>
1 parent 3040454 commit 63f2737

File tree

1 file changed

+32
-3
lines changed

1 file changed

+32
-3
lines changed

pkg/containerd/importer/importer.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,19 @@ func isLayerTar(name string) bool {
6060
return slashes == 2 && strings.HasSuffix(name, "/layer.tar")
6161
}
6262

63+
// followSymlinkLayer returns actual layer name of the symlink layer.
64+
func followSymlinkLayer(name string) (string, error) {
65+
parts := strings.Split(name, "/")
66+
if len(parts) != 3 || parts[0] != ".." {
67+
return "", errors.New("invalid symlink layer")
68+
}
69+
name = strings.TrimPrefix(name, "../")
70+
if !isLayerTar(name) {
71+
return "", errors.New("invalid layer tar")
72+
}
73+
return name, nil
74+
}
75+
6376
// isDotJSON returns true if name is like "deadbeefdeadbeef.json"
6477
func isDotJSON(name string) bool {
6578
slashes := len(strings.Split(name, "/"))
@@ -97,9 +110,10 @@ func Import(ctx context.Context, client *containerd.Client, reader io.Reader) (_
97110

98111
tr := tar.NewReader(reader)
99112
var (
100-
mfsts []manifestDotJSON
101-
layers = make(map[string]ocispec.Descriptor) // key: filename (deadbeeddeadbeef/layer.tar)
102-
configs = make(map[string]imageConfig) // key: filename (deadbeeddeadbeef.json)
113+
mfsts []manifestDotJSON
114+
symlinkLayers = make(map[string]string) // key: filename (deadbeeddeadbeef/layer.tar), value: linkname (targetlayerid/layer.tar)
115+
layers = make(map[string]ocispec.Descriptor) // key: filename (deadbeeddeadbeef/layer.tar)
116+
configs = make(map[string]imageConfig) // key: filename (deadbeeddeadbeef.json)
103117
)
104118
for {
105119
hdr, err := tr.Next()
@@ -109,6 +123,14 @@ func Import(ctx context.Context, client *containerd.Client, reader io.Reader) (_
109123
if err != nil {
110124
return nil, errors.Wrap(err, "get next file")
111125
}
126+
if hdr.Typeflag == tar.TypeSymlink && isLayerTar(hdr.Name) {
127+
linkname, err := followSymlinkLayer(hdr.Linkname)
128+
if err != nil {
129+
return nil, errors.Wrapf(err, "follow symlink layer from %q to %q", hdr.Name, hdr.Linkname)
130+
}
131+
symlinkLayers[hdr.Name] = linkname
132+
continue
133+
}
112134
if hdr.Typeflag != tar.TypeReg && hdr.Typeflag != tar.TypeRegA {
113135
continue
114136
}
@@ -136,6 +158,13 @@ func Import(ctx context.Context, client *containerd.Client, reader io.Reader) (_
136158
continue
137159
}
138160
}
161+
for name, linkname := range symlinkLayers {
162+
desc, ok := layers[linkname]
163+
if !ok {
164+
return nil, errors.Errorf("no target for symlink layer from %q to %q", name, linkname)
165+
}
166+
layers[name] = desc
167+
}
139168
var refs []string
140169
defer func() {
141170
if retErr == nil {

0 commit comments

Comments
 (0)