// list traverses the directory passed in, listing to out. // it returns a boolean whether it is finished or not. func (f *Fs) list(out fs.ListOpts, remote string, dirpath string, level int) (subdirs []listArgs) { fd, err := os.Open(dirpath) if err != nil { out.SetError(errors.Wrapf(err, "failed to open directory %q", dirpath)) return nil } defer func() { err := fd.Close() if err != nil { out.SetError(errors.Wrapf(err, "failed to close directory %q:", dirpath)) } }() for { fis, err := fd.Readdir(1024) if err == io.EOF && len(fis) == 0 { break } if err != nil { out.SetError(errors.Wrapf(err, "failed to read directory %q", dirpath)) return nil } for _, fi := range fis { name := fi.Name() newRemote := path.Join(remote, name) newPath := filepath.Join(dirpath, name) if fi.IsDir() { // Ignore directories which are symlinks. These are junction points under windows which // are kind of a souped up symlink. Unix doesn't have directories which are symlinks. if (fi.Mode()&os.ModeSymlink) == 0 && out.IncludeDirectory(newRemote) { dir := &fs.Dir{ Name: f.cleanRemote(newRemote), When: fi.ModTime(), Bytes: 0, Count: 0, } if out.AddDir(dir) { return nil } if level > 0 && f.dev == readDevice(fi) { subdirs = append(subdirs, listArgs{remote: newRemote, dirpath: newPath, level: level - 1}) } } } else { fso, err := f.newObjectWithInfo(newRemote, fi) if err != nil { out.SetError(err) return nil } if fso.Storable() && out.Add(fso) { return nil } } } } return subdirs }
// ListDir reads the directory specified by the job into out, returning any more jobs func (f *Fs) ListDir(out fs.ListOpts, job dircache.ListDirJob) (jobs []dircache.ListDirJob, err error) { fs.Debug(f, "Reading %q", job.Path) _, err = f.listAll(job.DirID, "", false, false, func(item *drive.File) bool { remote := job.Path + item.Title switch { case *driveAuthOwnerOnly && !isAuthOwned(item): // ignore object or directory case item.MimeType == driveFolderType: if out.IncludeDirectory(remote) { dir := &fs.Dir{ Name: remote, Bytes: -1, Count: -1, } dir.When, _ = time.Parse(timeFormatIn, item.ModifiedDate) if out.AddDir(dir) { return true } if job.Depth > 0 { jobs = append(jobs, dircache.ListDirJob{DirID: item.Id, Path: remote + "/", Depth: job.Depth - 1}) } } case item.Md5Checksum != "": // If item has MD5 sum it is a file stored on drive o, err := f.newObjectWithInfo(remote, item) if err != nil { out.SetError(err) return true } if out.Add(o) { return true } case len(item.ExportLinks) != 0: // If item has export links then it is a google doc extension, link := f.findExportFormat(remote, item) if extension == "" { fs.Debug(remote, "No export formats found") } else { o, err := f.newObjectWithInfo(remote+"."+extension, item) if err != nil { out.SetError(err) return true } obj := o.(*Object) obj.isDocument = true obj.url = link obj.bytes = -1 if out.Add(o) { return true } } default: fs.Debug(remote, "Ignoring unknown object") } return false }) fs.Debug(f, "Finished reading %q", job.Path) return jobs, err }
// list traverses the directory passed in, listing to out. // it returns a boolean whether it is finished or not. func (f *Fs) list(out fs.ListOpts, remote string, dirpath string, level int) (subdirs []listArgs) { fd, err := os.Open(dirpath) if err != nil { out.SetError(errors.Wrapf(err, "failed to open directory %q", dirpath)) return nil } defer func() { err := fd.Close() if err != nil { out.SetError(errors.Wrapf(err, "failed to close directory %q:", dirpath)) } }() for { fis, err := fd.Readdir(1024) if err == io.EOF && len(fis) == 0 { break } if err != nil { out.SetError(errors.Wrapf(err, "failed to read directory %q", dirpath)) return nil } for _, fi := range fis { name := fi.Name() newRemote := path.Join(remote, name) newPath := filepath.Join(dirpath, name) if fi.IsDir() { if out.IncludeDirectory(newRemote) { dir := &fs.Dir{ Name: normString(f.cleanUtf8(newRemote)), When: fi.ModTime(), Bytes: 0, Count: 0, } if out.AddDir(dir) { return nil } if level > 0 { subdirs = append(subdirs, listArgs{remote: newRemote, dirpath: newPath, level: level - 1}) } } } else { fso, err := f.newObjectWithInfo(newRemote, fi) if err != nil { out.SetError(err) return nil } if fso.Storable() && out.Add(fso) { return nil } } } } return subdirs }
// ListDir reads the directory specified by the job into out, returning any more jobs func (f *Fs) ListDir(out fs.ListOpts, job dircache.ListDirJob) (jobs []dircache.ListDirJob, err error) { fs.Debug(f, "Reading %q", job.Path) maxTries := fs.Config.LowLevelRetries for tries := 1; tries <= maxTries; tries++ { _, err = f.listAll(job.DirID, "", false, false, func(node *acd.Node) bool { remote := job.Path + *node.Name switch *node.Kind { case folderKind: if out.IncludeDirectory(remote) { dir := &fs.Dir{ Name: remote, Bytes: -1, Count: -1, } dir.When, _ = time.Parse(timeFormat, *node.ModifiedDate) // FIXME if out.AddDir(dir) { return true } if job.Depth > 0 { jobs = append(jobs, dircache.ListDirJob{DirID: *node.Id, Path: remote + "/", Depth: job.Depth - 1}) } } case fileKind: o, err := f.newObjectWithInfo(remote, node) if err != nil { out.SetError(err) return true } if out.Add(o) { return true } default: // ignore ASSET etc } return false }) if fs.IsRetryError(err) { fs.Debug(f, "Directory listing error for %q: %v - low level retry %d/%d", job.Path, err, tries, maxTries) continue } if err != nil { return nil, err } break } fs.Debug(f, "Finished reading %q", job.Path) return jobs, err }
// ListDir reads the directory specified by the job into out, returning any more jobs func (f *Fs) ListDir(out fs.ListOpts, job dircache.ListDirJob) (jobs []dircache.ListDirJob, err error) { fs.Debug(f, "Reading %q", job.Path) _, err = f.listAll(job.DirID, false, false, func(info *api.Item) bool { remote := job.Path + info.Name if info.Folder != nil { if out.IncludeDirectory(remote) { dir := &fs.Dir{ Name: remote, Bytes: -1, Count: -1, When: time.Time(info.LastModifiedDateTime), } if info.Folder != nil { dir.Count = info.Folder.ChildCount } if out.AddDir(dir) { return true } if job.Depth > 0 { jobs = append(jobs, dircache.ListDirJob{DirID: info.ID, Path: remote + "/", Depth: job.Depth - 1}) } } } else { o, err := f.newObjectWithInfo(remote, info) if err != nil { out.SetError(err) return true } if out.Add(o) { return true } } return false }) fs.Debug(f, "Finished reading %q", job.Path) return jobs, err }