github.com/pkg/sftp@v1.13.6/match.go (about) 1 package sftp 2 3 import ( 4 "path" 5 "strings" 6 ) 7 8 // ErrBadPattern indicates a globbing pattern was malformed. 9 var ErrBadPattern = path.ErrBadPattern 10 11 // Match reports whether name matches the shell pattern. 12 // 13 // This is an alias for path.Match from the standard library, 14 // offered so that callers need not import the path package. 15 // For details, see https://golang.org/pkg/path/#Match. 16 func Match(pattern, name string) (matched bool, err error) { 17 return path.Match(pattern, name) 18 } 19 20 // detect if byte(char) is path separator 21 func isPathSeparator(c byte) bool { 22 return c == '/' 23 } 24 25 // Split splits the path p immediately following the final slash, 26 // separating it into a directory and file name component. 27 // 28 // This is an alias for path.Split from the standard library, 29 // offered so that callers need not import the path package. 30 // For details, see https://golang.org/pkg/path/#Split. 31 func Split(p string) (dir, file string) { 32 return path.Split(p) 33 } 34 35 // Glob returns the names of all files matching pattern or nil 36 // if there is no matching file. The syntax of patterns is the same 37 // as in Match. The pattern may describe hierarchical names such as 38 // /usr/*/bin/ed. 39 // 40 // Glob ignores file system errors such as I/O errors reading directories. 41 // The only possible returned error is ErrBadPattern, when pattern 42 // is malformed. 43 func (c *Client) Glob(pattern string) (matches []string, err error) { 44 if !hasMeta(pattern) { 45 file, err := c.Lstat(pattern) 46 if err != nil { 47 return nil, nil 48 } 49 dir, _ := Split(pattern) 50 dir = cleanGlobPath(dir) 51 return []string{Join(dir, file.Name())}, nil 52 } 53 54 dir, file := Split(pattern) 55 dir = cleanGlobPath(dir) 56 57 if !hasMeta(dir) { 58 return c.glob(dir, file, nil) 59 } 60 61 // Prevent infinite recursion. See issue 15879. 62 if dir == pattern { 63 return nil, ErrBadPattern 64 } 65 66 var m []string 67 m, err = c.Glob(dir) 68 if err != nil { 69 return 70 } 71 for _, d := range m { 72 matches, err = c.glob(d, file, matches) 73 if err != nil { 74 return 75 } 76 } 77 return 78 } 79 80 // cleanGlobPath prepares path for glob matching. 81 func cleanGlobPath(path string) string { 82 switch path { 83 case "": 84 return "." 85 case "/": 86 return path 87 default: 88 return path[0 : len(path)-1] // chop off trailing separator 89 } 90 } 91 92 // glob searches for files matching pattern in the directory dir 93 // and appends them to matches. If the directory cannot be 94 // opened, it returns the existing matches. New matches are 95 // added in lexicographical order. 96 func (c *Client) glob(dir, pattern string, matches []string) (m []string, e error) { 97 m = matches 98 fi, err := c.Stat(dir) 99 if err != nil { 100 return 101 } 102 if !fi.IsDir() { 103 return 104 } 105 names, err := c.ReadDir(dir) 106 if err != nil { 107 return 108 } 109 //sort.Strings(names) 110 111 for _, n := range names { 112 matched, err := Match(pattern, n.Name()) 113 if err != nil { 114 return m, err 115 } 116 if matched { 117 m = append(m, Join(dir, n.Name())) 118 } 119 } 120 return 121 } 122 123 // Join joins any number of path elements into a single path, separating 124 // them with slashes. 125 // 126 // This is an alias for path.Join from the standard library, 127 // offered so that callers need not import the path package. 128 // For details, see https://golang.org/pkg/path/#Join. 129 func Join(elem ...string) string { 130 return path.Join(elem...) 131 } 132 133 // hasMeta reports whether path contains any of the magic characters 134 // recognized by Match. 135 func hasMeta(path string) bool { 136 return strings.ContainsAny(path, "\\*?[") 137 }