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 }