mirror of
https://github.com/rclone/rclone.git
synced 2024-11-29 20:04:52 +01:00
753b0717be
Gives more accurate error propagation, control of depth of recursion and short circuit recursion where possible. Most of the the heavy lifting is done in the "fs" package, making file system implementations a bit simpler. This commit contains some code originally by Klaus Post. Fixes #316
75 lines
1.8 KiB
Go
75 lines
1.8 KiB
Go
// Listing utility functions for fses which use dircache
|
|
|
|
package dircache
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/ncw/rclone/fs"
|
|
)
|
|
|
|
// ListDirJob describe a directory listing that needs to be done
|
|
type ListDirJob struct {
|
|
DirID string
|
|
Path string
|
|
Depth int
|
|
}
|
|
|
|
// ListDirer describes the interface necessary to use ListDir
|
|
type ListDirer interface {
|
|
// ListDir reads the directory specified by the job into out, returning any more jobs
|
|
ListDir(out fs.ListOpts, job ListDirJob) (jobs []ListDirJob, err error)
|
|
}
|
|
|
|
// listDir lists the directory using a recursive list from the root
|
|
//
|
|
// It does this in parallel, calling f.ListDir to do the actual reading
|
|
func listDir(f ListDirer, out fs.ListOpts, dirID string, path string) {
|
|
// Start some directory listing go routines
|
|
var wg sync.WaitGroup // sync closing of go routines
|
|
var traversing sync.WaitGroup // running directory traversals
|
|
buffer := out.Buffer()
|
|
in := make(chan ListDirJob, buffer)
|
|
for i := 0; i < buffer; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
for job := range in {
|
|
jobs, err := f.ListDir(out, job)
|
|
if err != nil {
|
|
out.SetError(err)
|
|
fs.Debug(f, "Error reading %s: %s", path, err)
|
|
} else {
|
|
traversing.Add(len(jobs))
|
|
go func() {
|
|
// Now we have traversed this directory, send these
|
|
// jobs off for traversal in the background
|
|
for _, job := range jobs {
|
|
in <- job
|
|
}
|
|
}()
|
|
}
|
|
traversing.Done()
|
|
}
|
|
}()
|
|
}
|
|
|
|
// Start the process
|
|
traversing.Add(1)
|
|
in <- ListDirJob{DirID: dirID, Path: path, Depth: out.Level() - 1}
|
|
traversing.Wait()
|
|
close(in)
|
|
wg.Wait()
|
|
}
|
|
|
|
// List walks the path returning iles and directories into out
|
|
func (dc *DirCache) List(f ListDirer, out fs.ListOpts) {
|
|
defer out.Finished()
|
|
err := dc.FindRoot(false)
|
|
if err != nil {
|
|
out.SetError(fs.ErrorDirNotFound)
|
|
} else {
|
|
listDir(f, out, dc.RootID(), "")
|
|
}
|
|
}
|