forked from TrueCloudLab/restic
Merge pull request #3065 from greatroar/local-subdirs
Don't recurse in local backend's List if not required
This commit is contained in:
commit
f2959127b6
1 changed files with 61 additions and 41 deletions
|
@ -220,53 +220,18 @@ func (b *Local) Remove(ctx context.Context, h restic.Handle) error {
|
|||
return fs.Remove(fn)
|
||||
}
|
||||
|
||||
func isFile(fi os.FileInfo) bool {
|
||||
return fi.Mode()&(os.ModeType|os.ModeCharDevice) == 0
|
||||
}
|
||||
|
||||
// List runs fn for each file in the backend which has the type t. When an
|
||||
// error occurs (or fn returns an error), List stops and returns it.
|
||||
func (b *Local) List(ctx context.Context, t restic.FileType, fn func(restic.FileInfo) error) error {
|
||||
func (b *Local) List(ctx context.Context, t restic.FileType, fn func(restic.FileInfo) error) (err error) {
|
||||
debug.Log("List %v", t)
|
||||
|
||||
basedir, subdirs := b.Basedir(t)
|
||||
err := fs.Walk(basedir, func(path string, fi os.FileInfo, err error) error {
|
||||
debug.Log("walk on %v\n", path)
|
||||
if err != nil {
|
||||
return err
|
||||
if subdirs {
|
||||
err = visitDirs(ctx, basedir, fn)
|
||||
} else {
|
||||
err = visitFiles(ctx, basedir, fn)
|
||||
}
|
||||
|
||||
if path == basedir {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !isFile(fi) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if fi.IsDir() && !subdirs {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
|
||||
debug.Log("send %v\n", filepath.Base(path))
|
||||
|
||||
rfi := restic.FileInfo{
|
||||
Name: filepath.Base(path),
|
||||
Size: fi.Size(),
|
||||
}
|
||||
|
||||
if ctx.Err() != nil {
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
err = fn(rfi)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ctx.Err()
|
||||
})
|
||||
|
||||
if b.IsNotExist(err) {
|
||||
debug.Log("ignoring non-existing directory")
|
||||
return nil
|
||||
|
@ -275,6 +240,61 @@ func (b *Local) List(ctx context.Context, t restic.FileType, fn func(restic.File
|
|||
return err
|
||||
}
|
||||
|
||||
// The following two functions are like filepath.Walk, but visit only one or
|
||||
// two levels of directory structure (including dir itself as the first level).
|
||||
// Also, visitDirs assumes it sees a directory full of directories, while
|
||||
// visitFiles wants a directory full or regular files.
|
||||
func visitDirs(ctx context.Context, dir string, fn func(restic.FileInfo) error) error {
|
||||
d, err := fs.Open(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
sub, err := d.Readdirnames(-1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, f := range sub {
|
||||
err = visitFiles(ctx, filepath.Join(dir, f), fn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
func visitFiles(ctx context.Context, dir string, fn func(restic.FileInfo) error) error {
|
||||
d, err := fs.Open(dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
sub, err := d.Readdir(-1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, fi := range sub {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
err := fn(restic.FileInfo{
|
||||
Name: fi.Name(),
|
||||
Size: fi.Size(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete removes the repository and all files.
|
||||
func (b *Local) Delete(ctx context.Context) error {
|
||||
debug.Log("Delete()")
|
||||
|
|
Loading…
Reference in a new issue