github.com/tych0/umoci@v0.4.2/pkg/mtreefilter/mask.go (about)

     1  /*
     2   * umoci: Umoci Modifies Open Containers' Images
     3   * Copyright (C) 2017, 2018 SUSE LLC.
     4   *
     5   * Licensed under the Apache License, Version 2.0 (the "License");
     6   * you may not use this file except in compliance with the License.
     7   * You may obtain a copy of the License at
     8   *
     9   *    http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17  
    18  package mtreefilter
    19  
    20  import (
    21  	"path/filepath"
    22  
    23  	"github.com/apex/log"
    24  	"github.com/vbatts/go-mtree"
    25  )
    26  
    27  // FilterFunc is a function used when filtering deltas with FilterDeltas.
    28  type FilterFunc func(path string) bool
    29  
    30  // makeRoot does a very simple job of converting a path to a lexical
    31  // relative-to-root. In mtree we don't deal with any symlink components.
    32  func makeRoot(path string) string {
    33  	return filepath.Join(string(filepath.Separator), path)
    34  }
    35  
    36  func maskFilter(maskedPaths map[string]struct{}, includeSelf bool) FilterFunc {
    37  	return func(path string) bool {
    38  		// Convert the path to be cleaned and relative-to-root.
    39  		path = makeRoot(path)
    40  
    41  		// Check that no ancestor of the path is a masked path.
    42  		for parent := path; parent != filepath.Dir(parent); parent = filepath.Dir(parent) {
    43  			if _, ok := maskedPaths[parent]; !ok {
    44  				continue
    45  			}
    46  			if parent == path && !includeSelf {
    47  				continue
    48  			}
    49  			log.Debugf("maskfilter: ignoring path %q matched by mask %q", path, parent)
    50  			return false
    51  		}
    52  		return true
    53  	}
    54  }
    55  
    56  // MaskFilter is a factory for FilterFuncs that will mask all InodeDelta paths
    57  // that are lexical children of any path in the mask slice. All paths are
    58  // considered to be relative to '/'.
    59  func MaskFilter(masks []string) FilterFunc {
    60  	maskedPaths := map[string]struct{}{}
    61  	for _, mask := range masks {
    62  		maskedPaths[makeRoot(mask)] = struct{}{}
    63  	}
    64  	return maskFilter(maskedPaths, true)
    65  }
    66  
    67  // SimplifyFilter is a factory that takes a list of InodeDelta and creates a
    68  // filter to filter out all deletion entries that have a parent which also has
    69  // a deletion entry. This is necessary to both reduce our image sizes and
    70  // remain compatible with Docker's now-incompatible image format (the OCI spec
    71  // doesn't require this behaviour but it's now needed because of course Docker
    72  // won't fix their own bugs).
    73  func SimplifyFilter(deltas []mtree.InodeDelta) FilterFunc {
    74  	deletedPaths := make(map[string]struct{})
    75  	for _, delta := range deltas {
    76  		if delta.Type() != mtree.Missing {
    77  			continue
    78  		}
    79  		deletedPaths[makeRoot(delta.Path())] = struct{}{}
    80  	}
    81  	return maskFilter(deletedPaths, false)
    82  }
    83  
    84  // FilterDeltas is a helper function to easily filter []mtree.InodeDelta with a
    85  // filter function. Only entries which have `filter(delta.Path()) == true` will
    86  // be included in the returned slice.
    87  func FilterDeltas(deltas []mtree.InodeDelta, filters ...FilterFunc) []mtree.InodeDelta {
    88  	var filtered []mtree.InodeDelta
    89  	for _, delta := range deltas {
    90  		var blocked bool
    91  		for _, filter := range filters {
    92  			if !filter(delta.Path()) {
    93  				blocked = true
    94  				break
    95  			}
    96  		}
    97  		if !blocked {
    98  			filtered = append(filtered, delta)
    99  		}
   100  	}
   101  	return filtered
   102  }