github.com/rigado/snapd@v2.42.5-go-mod+incompatible/asserts/findwildcard.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2015 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package asserts 21 22 import ( 23 "fmt" 24 "os" 25 "path/filepath" 26 "strings" 27 ) 28 29 /* 30 findWildcard invokes foundCb once for each parent directory of regular files matching: 31 32 <top>/<descendantWithWildcard[0]>/<descendantWithWildcard[1]>... 33 34 where each descendantWithWildcard component can contain the * wildcard; 35 36 foundCb is invoked with the paths of the found regular files relative to top (that means top/ is excluded). 37 38 Unlike filepath.Glob any I/O operation error stops the walking and bottoms out, so does a foundCb invocation that returns an error. 39 */ 40 func findWildcard(top string, descendantWithWildcard []string, foundCb func(relpath []string) error) error { 41 return findWildcardDescend(top, top, descendantWithWildcard, foundCb) 42 } 43 44 func findWildcardBottom(top, current string, pat string, names []string, foundCb func(relpath []string) error) error { 45 var hits []string 46 for _, name := range names { 47 ok, err := filepath.Match(pat, name) 48 if err != nil { 49 return fmt.Errorf("findWildcard: invoked with malformed wildcard: %v", err) 50 } 51 if !ok { 52 continue 53 } 54 fn := filepath.Join(current, name) 55 finfo, err := os.Stat(fn) 56 if os.IsNotExist(err) { 57 continue 58 } 59 if err != nil { 60 return err 61 } 62 if !finfo.Mode().IsRegular() { 63 return fmt.Errorf("expected a regular file: %v", fn) 64 } 65 relpath, err := filepath.Rel(top, fn) 66 if err != nil { 67 return fmt.Errorf("findWildcard: unexpected to fail at computing rel path of descendant") 68 } 69 hits = append(hits, relpath) 70 } 71 if len(hits) == 0 { 72 return nil 73 } 74 return foundCb(hits) 75 } 76 77 func findWildcardDescend(top, current string, descendantWithWildcard []string, foundCb func(relpath []string) error) error { 78 k := descendantWithWildcard[0] 79 if len(descendantWithWildcard) > 1 && strings.IndexByte(k, '*') == -1 { 80 return findWildcardDescend(top, filepath.Join(current, k), descendantWithWildcard[1:], foundCb) 81 } 82 83 d, err := os.Open(current) 84 if os.IsNotExist(err) { 85 return nil 86 } 87 if err != nil { 88 return err 89 } 90 defer d.Close() 91 names, err := d.Readdirnames(-1) 92 if err != nil { 93 return err 94 } 95 if len(descendantWithWildcard) == 1 { 96 return findWildcardBottom(top, current, k, names, foundCb) 97 } 98 for _, name := range names { 99 ok, err := filepath.Match(k, name) 100 if err != nil { 101 return fmt.Errorf("findWildcard: invoked with malformed wildcard: %v", err) 102 } 103 if ok { 104 err = findWildcardDescend(top, filepath.Join(current, name), descendantWithWildcard[1:], foundCb) 105 if err != nil { 106 return err 107 } 108 } 109 } 110 return nil 111 }