github.com/containerd/Containerd@v1.4.13/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/containerd/containerd/sys"
    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 sys.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  }