From e6578857cf18e818f2cfe11cd7fb17ec173a600f Mon Sep 17 00:00:00 2001 From: Alexander Neumann Date: Mon, 10 Apr 2017 23:31:13 +0200 Subject: [PATCH] sftp/local: Fix listing files --- src/restic/backend/local/local.go | 79 ++++--------------------------- src/restic/backend/sftp/sftp.go | 65 ++++++------------------- 2 files changed, 24 insertions(+), 120 deletions(-) diff --git a/src/restic/backend/local/local.go b/src/restic/backend/local/local.go index a8b9f4501..b140fd8f8 100644 --- a/src/restic/backend/local/local.go +++ b/src/restic/backend/local/local.go @@ -210,91 +210,30 @@ func isFile(fi os.FileInfo) bool { return fi.Mode()&(os.ModeType|os.ModeCharDevice) == 0 } -func readdir(d string) (fileInfos []os.FileInfo, err error) { - f, e := fs.Open(d) - if e != nil { - return nil, errors.Wrap(e, "Open") - } - - defer func() { - e := f.Close() - if err == nil { - err = errors.Wrap(e, "Close") - } - }() - - return f.Readdir(-1) -} - -// listDir returns a list of all files in d. -func listDir(d string) (filenames []string, err error) { - fileInfos, err := readdir(d) - if err != nil { - return nil, err - } - - for _, fi := range fileInfos { - if isFile(fi) { - filenames = append(filenames, fi.Name()) - } - } - - return filenames, nil -} - -// listDirs returns a list of all files in directories within d. -func listDirs(dir string) (filenames []string, err error) { - fileInfos, err := readdir(dir) - if err != nil { - return nil, err - } - - for _, fi := range fileInfos { - if !fi.IsDir() { - continue - } - - files, err := listDir(filepath.Join(dir, fi.Name())) - if err != nil { - continue - } - - filenames = append(filenames, files...) - } - - return filenames, nil -} - // List returns a channel that yields all names of blobs of type t. A // goroutine is started for this. If the channel done is closed, sending // stops. func (b *Local) List(t restic.FileType, done <-chan struct{}) <-chan string { debug.Log("List %v", t) - lister := listDir - if t == restic.DataFile { - lister = listDirs - } ch := make(chan string) - items, err := lister(b.Dirname(restic.Handle{Type: t})) - if err != nil { - close(ch) - return ch - } go func() { defer close(ch) - for _, m := range items { - if m == "" { - continue + + fs.Walk(b.Basedir(t), func(path string, fi os.FileInfo, err error) error { + if !isFile(fi) { + return err } select { - case ch <- m: + case ch <- filepath.Base(path): case <-done: - return + return err } - } + + return err + }) }() return ch diff --git a/src/restic/backend/sftp/sftp.go b/src/restic/backend/sftp/sftp.go index f9a8efd14..297f33f29 100644 --- a/src/restic/backend/sftp/sftp.go +++ b/src/restic/backend/sftp/sftp.go @@ -7,6 +7,7 @@ import ( "os" "os/exec" "path" + "path/filepath" "restic" "strings" "time" @@ -434,64 +435,28 @@ func (r *SFTP) Remove(h restic.Handle) error { // goroutine is started for this. If the channel done is closed, sending // stops. func (r *SFTP) List(t restic.FileType, done <-chan struct{}) <-chan string { - debug.Log("list all %v", t) + debug.Log("List %v", t) + ch := make(chan string) go func() { defer close(ch) - if t == restic.DataFile { - // read first level - basedir := r.Dirname(restic.Handle{Type: t}) + walker := r.c.Walk(r.Basedir(t)) + for walker.Step() { + if walker.Err() != nil { + continue + } - list1, err := r.c.ReadDir(basedir) - if err != nil { + if !walker.Stat().Mode().IsRegular() { + continue + } + + select { + case ch <- filepath.Base(walker.Path()): + case <-done: return } - - dirs := make([]string, 0, len(list1)) - for _, d := range list1 { - dirs = append(dirs, d.Name()) - } - - // read files - for _, dir := range dirs { - entries, err := r.c.ReadDir(Join(basedir, dir)) - if err != nil { - continue - } - - items := make([]string, 0, len(entries)) - for _, entry := range entries { - items = append(items, entry.Name()) - } - - for _, file := range items { - select { - case ch <- file: - case <-done: - return - } - } - } - } else { - entries, err := r.c.ReadDir(r.Dirname(restic.Handle{Type: t})) - if err != nil { - return - } - - items := make([]string, 0, len(entries)) - for _, entry := range entries { - items = append(items, entry.Name()) - } - - for _, file := range items { - select { - case ch <- file: - case <-done: - return - } - } } }()