sftp/local: Fix listing files

This commit is contained in:
Alexander Neumann 2017-04-10 23:31:13 +02:00
parent 320c22f1f5
commit e6578857cf
2 changed files with 24 additions and 120 deletions

View file

@ -210,91 +210,30 @@ func isFile(fi os.FileInfo) bool {
return fi.Mode()&(os.ModeType|os.ModeCharDevice) == 0 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 // 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 // goroutine is started for this. If the channel done is closed, sending
// stops. // stops.
func (b *Local) List(t restic.FileType, done <-chan struct{}) <-chan string { func (b *Local) List(t restic.FileType, done <-chan struct{}) <-chan string {
debug.Log("List %v", t) debug.Log("List %v", t)
lister := listDir
if t == restic.DataFile {
lister = listDirs
}
ch := make(chan string) ch := make(chan string)
items, err := lister(b.Dirname(restic.Handle{Type: t}))
if err != nil {
close(ch)
return ch
}
go func() { go func() {
defer close(ch) defer close(ch)
for _, m := range items {
if m == "" { fs.Walk(b.Basedir(t), func(path string, fi os.FileInfo, err error) error {
continue if !isFile(fi) {
return err
} }
select { select {
case ch <- m: case ch <- filepath.Base(path):
case <-done: case <-done:
return return err
}
} }
return err
})
}() }()
return ch return ch

View file

@ -7,6 +7,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"path" "path"
"path/filepath"
"restic" "restic"
"strings" "strings"
"time" "time"
@ -434,65 +435,29 @@ func (r *SFTP) Remove(h restic.Handle) error {
// goroutine is started for this. If the channel done is closed, sending // goroutine is started for this. If the channel done is closed, sending
// stops. // stops.
func (r *SFTP) List(t restic.FileType, done <-chan struct{}) <-chan string { 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) ch := make(chan string)
go func() { go func() {
defer close(ch) defer close(ch)
if t == restic.DataFile { walker := r.c.Walk(r.Basedir(t))
// read first level for walker.Step() {
basedir := r.Dirname(restic.Handle{Type: t}) if walker.Err() != nil {
list1, err := r.c.ReadDir(basedir)
if err != nil {
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 continue
} }
items := make([]string, 0, len(entries)) if !walker.Stat().Mode().IsRegular() {
for _, entry := range entries { continue
items = append(items, entry.Name())
} }
for _, file := range items {
select { select {
case ch <- file: case ch <- filepath.Base(walker.Path()):
case <-done: case <-done:
return 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
}
}
}
}() }()
return ch return ch