match.go 3.3 KB

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