// List the path into out // // Ignores everything which isn't Storable, eg links etc func (f *Fs) List(out fs.ListOpts, dir string) { defer out.Finished() dir = filterFragment(f.cleanUtf8(dir)) root := filepath.Join(f.root, dir) _, err := os.Stat(root) if err != nil { out.SetError(fs.ErrorDirNotFound) return } in := make(chan listArgs, out.Buffer()) var wg sync.WaitGroup // sync closing of go routines var traversing sync.WaitGroup // running directory traversals // Start the process traversing.Add(1) in <- listArgs{remote: dir, dirpath: root, level: out.Level() - 1} for i := 0; i < fs.Config.Checkers; i++ { wg.Add(1) go func() { defer wg.Done() for job := range in { if out.IsFinished() { continue } newJobs := f.list(out, job.remote, job.dirpath, job.level) // Now we have traversed this directory, send // these ones off for traversal if len(newJobs) != 0 { traversing.Add(len(newJobs)) go func() { for _, newJob := range newJobs { in <- newJob } }() } traversing.Done() } }() } // Wait for traversal to finish traversing.Wait() close(in) wg.Wait() }
// 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() }