mirror of https://github.com/restic/restic.git
sftp/local: Fix listing files
This commit is contained in:
parent
320c22f1f5
commit
e6578857cf
|
@ -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
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
|
"path/filepath"
|
||||||
"restic"
|
"restic"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"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
|
// 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 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
list1, err := r.c.ReadDir(basedir)
|
if !walker.Stat().Mode().IsRegular() {
|
||||||
if err != nil {
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case ch <- filepath.Base(walker.Path()):
|
||||||
|
case <-done:
|
||||||
return
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue