github.com/demonoid81/containerd@v1.3.4/diff/apply/apply_linux.go (about) 1 // +build linux 2 3 /* 4 Copyright The containerd Authors. 5 6 Licensed under the Apache License, Version 2.0 (the "License"); 7 you may not use this file except in compliance with the License. 8 You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 See the License for the specific language governing permissions and 16 limitations under the License. 17 */ 18 19 package apply 20 21 import ( 22 "context" 23 "io" 24 "strings" 25 26 "github.com/containerd/containerd/archive" 27 "github.com/containerd/containerd/errdefs" 28 "github.com/containerd/containerd/mount" 29 "github.com/opencontainers/runc/libcontainer/system" 30 "github.com/pkg/errors" 31 ) 32 33 func apply(ctx context.Context, mounts []mount.Mount, r io.Reader) error { 34 switch { 35 case len(mounts) == 1 && mounts[0].Type == "overlay": 36 // OverlayConvertWhiteout (mknod c 0 0) doesn't work in userns. 37 // https://github.com/containerd/containerd/issues/3762 38 if system.RunningInUserNS() { 39 break 40 } 41 path, parents, err := getOverlayPath(mounts[0].Options) 42 if err != nil { 43 if errdefs.IsInvalidArgument(err) { 44 break 45 } 46 return err 47 } 48 opts := []archive.ApplyOpt{ 49 archive.WithConvertWhiteout(archive.OverlayConvertWhiteout), 50 } 51 if len(parents) > 0 { 52 opts = append(opts, archive.WithParents(parents)) 53 } 54 _, err = archive.Apply(ctx, path, r, opts...) 55 return err 56 case len(mounts) == 1 && mounts[0].Type == "aufs": 57 path, parents, err := getAufsPath(mounts[0].Options) 58 if err != nil { 59 if errdefs.IsInvalidArgument(err) { 60 break 61 } 62 return err 63 } 64 opts := []archive.ApplyOpt{ 65 archive.WithConvertWhiteout(archive.AufsConvertWhiteout), 66 } 67 if len(parents) > 0 { 68 opts = append(opts, archive.WithParents(parents)) 69 } 70 _, err = archive.Apply(ctx, path, r, opts...) 71 return err 72 } 73 return mount.WithTempMount(ctx, mounts, func(root string) error { 74 _, err := archive.Apply(ctx, root, r) 75 return err 76 }) 77 } 78 79 func getOverlayPath(options []string) (upper string, lower []string, err error) { 80 const upperdirPrefix = "upperdir=" 81 const lowerdirPrefix = "lowerdir=" 82 83 for _, o := range options { 84 if strings.HasPrefix(o, upperdirPrefix) { 85 upper = strings.TrimPrefix(o, upperdirPrefix) 86 } else if strings.HasPrefix(o, lowerdirPrefix) { 87 lower = strings.Split(strings.TrimPrefix(o, lowerdirPrefix), ":") 88 } 89 } 90 if upper == "" { 91 return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "upperdir not found") 92 } 93 94 return 95 } 96 97 // getAufsPath handles options as given by the containerd aufs package only, 98 // formatted as "br:<upper>=rw[:<lower>=ro+wh]*" 99 func getAufsPath(options []string) (upper string, lower []string, err error) { 100 const ( 101 sep = ":" 102 brPrefix = "br:" 103 rwSuffix = "=rw" 104 roSuffix = "=ro+wh" 105 ) 106 for _, o := range options { 107 if strings.HasPrefix(o, brPrefix) { 108 o = strings.TrimPrefix(o, brPrefix) 109 } else { 110 continue 111 } 112 113 for _, b := range strings.Split(o, sep) { 114 if strings.HasSuffix(b, rwSuffix) { 115 if upper != "" { 116 return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "multiple rw branch found") 117 } 118 upper = strings.TrimSuffix(b, rwSuffix) 119 } else if strings.HasSuffix(b, roSuffix) { 120 if upper == "" { 121 return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "rw branch be first") 122 } 123 lower = append(lower, strings.TrimSuffix(b, roSuffix)) 124 } else { 125 return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "unhandled aufs suffix") 126 } 127 128 } 129 } 130 if upper == "" { 131 return "", nil, errors.Wrap(errdefs.ErrInvalidArgument, "rw branch not found") 132 } 133 return 134 }