Source file
src/io/fs/glob.go
1
2
3
4
5 package fs
6
7 import (
8 "path"
9 )
10
11
12 type GlobFS interface {
13 FS
14
15
16
17
18 Glob(pattern string) ([]string, error)
19 }
20
21
22
23
24
25
26
27
28
29
30
31
32
33 func Glob(fsys FS, pattern string) (matches []string, err error) {
34 return globWithLimit(fsys, pattern, 0)
35 }
36
37 func globWithLimit(fsys FS, pattern string, depth int) (matches []string, err error) {
38
39
40 const pathSeparatorsLimit = 10000
41 if depth > pathSeparatorsLimit {
42 return nil, path.ErrBadPattern
43 }
44 if fsys, ok := fsys.(GlobFS); ok {
45 return fsys.Glob(pattern)
46 }
47
48
49 if _, err := path.Match(pattern, ""); err != nil {
50 return nil, err
51 }
52 if !hasMeta(pattern) {
53 if _, err = Stat(fsys, pattern); err != nil {
54 return nil, nil
55 }
56 return []string{pattern}, nil
57 }
58
59 dir, file := path.Split(pattern)
60 dir = cleanGlobPath(dir)
61
62 if !hasMeta(dir) {
63 return glob(fsys, dir, file, nil)
64 }
65
66
67 if dir == pattern {
68 return nil, path.ErrBadPattern
69 }
70
71 var m []string
72 m, err = globWithLimit(fsys, dir, depth+1)
73 if err != nil {
74 return nil, err
75 }
76 for _, d := range m {
77 matches, err = glob(fsys, d, file, matches)
78 if err != nil {
79 return
80 }
81 }
82 return
83 }
84
85
86 func cleanGlobPath(path string) string {
87 switch path {
88 case "":
89 return "."
90 default:
91 return path[0 : len(path)-1]
92 }
93 }
94
95
96
97
98
99 func glob(fs FS, dir, pattern string, matches []string) (m []string, e error) {
100 m = matches
101 infos, err := ReadDir(fs, dir)
102 if err != nil {
103 return
104 }
105
106 for _, info := range infos {
107 n := info.Name()
108 matched, err := path.Match(pattern, n)
109 if err != nil {
110 return m, err
111 }
112 if matched {
113 m = append(m, path.Join(dir, n))
114 }
115 }
116 return
117 }
118
119
120
121 func hasMeta(path string) bool {
122 for i := 0; i < len(path); i++ {
123 switch path[i] {
124 case '*', '?', '[', '\\':
125 return true
126 }
127 }
128 return false
129 }
130
View as plain text