@@ -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"
6477func 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