walker.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. package ftp
  2. import (
  3. pa "path"
  4. "strings"
  5. )
  6. //Walker traverses the directory tree of a remote FTP server
  7. type Walker struct {
  8. serverConn *ServerConn
  9. root string
  10. cur item
  11. stack []item
  12. descend bool
  13. }
  14. type item struct {
  15. path string
  16. entry Entry
  17. err error
  18. }
  19. // Next advances the Walker to the next file or directory,
  20. // which will then be available through the Path, Stat, and Err methods.
  21. // It returns false when the walk stops at the end of the tree.
  22. func (w *Walker) Next() bool {
  23. if w.descend && w.cur.err == nil && w.cur.entry.Type == EntryTypeFolder {
  24. list, err := w.serverConn.List(w.cur.path)
  25. if err != nil {
  26. w.cur.err = err
  27. w.stack = append(w.stack, w.cur)
  28. } else {
  29. for i := len(list) - 1; i >= 0; i-- {
  30. if !strings.HasSuffix(w.cur.path, "/") {
  31. w.cur.path += "/"
  32. }
  33. var path string
  34. if list[i].Type == EntryTypeFolder {
  35. path = pa.Join(w.cur.path, list[i].Name)
  36. } else {
  37. path = w.cur.path
  38. }
  39. w.stack = append(w.stack, item{path, *list[i], nil})
  40. }
  41. }
  42. }
  43. if len(w.stack) == 0 {
  44. return false
  45. }
  46. i := len(w.stack) - 1
  47. w.cur = w.stack[i]
  48. w.stack = w.stack[:i]
  49. w.descend = true
  50. return true
  51. }
  52. //SkipDir tells the Next function to skip the currently processed directory
  53. func (w *Walker) SkipDir() {
  54. w.descend = false
  55. }
  56. //Err returns the error, if any, for the most recent attempt by Next to
  57. //visit a file or a directory. If a directory has an error, the walker
  58. //will not descend in that directory
  59. func (w *Walker) Err() error {
  60. return w.cur.err
  61. }
  62. // Stat returns info for the most recent file or directory
  63. // visited by a call to Step.
  64. func (w *Walker) Stat() Entry {
  65. return w.cur.entry
  66. }
  67. // Path returns the path to the most recent file or directory
  68. // visited by a call to Next. It contains the argument to Walk
  69. // as a prefix; that is, if Walk is called with "dir", which is
  70. // a directory containing the file "a", Path will return "dir/a".
  71. func (w *Walker) Path() string {
  72. return w.cur.path
  73. }