@@ -1979,25 +1979,28 @@ func (f *Fs) itemToDirEntry(ctx context.Context, remote string, object *s3.Objec
19791979 return o , nil
19801980}
19811981
1982- // listDir lists files and directories to out
1983- func (f * Fs ) listDir (ctx context.Context , bucket , directory , prefix string , addBucket bool ) (entries fs.DirEntries , err error ) {
1984- // List the objects and directories
1985- err = f .list (ctx , bucket , directory , prefix , addBucket , false , func (remote string , object * s3.Object , isDirectory bool ) error {
1982+ // listDirCB calls callback on files as they are being listed.
1983+ func (f * Fs ) listDir (ctx context.Context , bucket , directory , prefix string , addBucket bool , cb fs.ListCBCallback ) error {
1984+ // List the objects and directories.
1985+ // Batch callbacks by 100 with walk.NewListRHelper (compatible callback type)
1986+ // in order to reduce the amount of allocations and function calls.
1987+ list := walk .NewListRHelper (fs .ListRCallback (cb ))
1988+ err := f .list (ctx , bucket , directory , prefix , addBucket , false , func (remote string , object * s3.Object , isDirectory bool ) error {
19861989 entry , err := f .itemToDirEntry (ctx , remote , object , isDirectory )
19871990 if err != nil {
19881991 return err
19891992 }
19901993 if entry != nil {
1991- entries = append ( entries , entry )
1994+ return list . Add ( entry )
19921995 }
19931996 return nil
19941997 })
19951998 if err != nil {
1996- return nil , err
1999+ return err
19972000 }
19982001 // bucket must be present if listing succeeded
19992002 f .cache .MarkOK (bucket )
2000- return entries , nil
2003+ return list . Flush ()
20012004}
20022005
20032006// listBuckets lists the buckets to out
@@ -2029,15 +2032,48 @@ func (f *Fs) listBuckets(ctx context.Context) (entries fs.DirEntries, err error)
20292032//
20302033// This should return ErrDirNotFound if the directory isn't
20312034// found.
2032- func (f * Fs ) List (ctx context.Context , dir string ) (entries fs.DirEntries , err error ) {
2035+ func (f * Fs ) List (ctx context.Context , dir string ) (fs.DirEntries , error ) {
20332036 bucket , directory := f .split (dir )
20342037 if bucket == "" {
20352038 if directory != "" {
20362039 return nil , fs .ErrorListBucketRequired
20372040 }
20382041 return f .listBuckets (ctx )
20392042 }
2040- return f .listDir (ctx , bucket , directory , f .rootDirectory , f .rootBucket == "" )
2043+
2044+ // Use callback for regular listing
2045+ var entries fs.DirEntries
2046+ err := f .listDir (ctx , bucket , directory , f .rootDirectory , f .rootBucket == "" , func (e fs.DirEntries ) error {
2047+ entries = append (entries , e ... )
2048+ return nil
2049+ })
2050+ if err != nil {
2051+ return nil , err
2052+ }
2053+ return entries , nil
2054+ }
2055+
2056+ // ListCB calls callback to the objects and directories in dir as they are being listed.
2057+ // The callback might be called for just a subset of directory entries.
2058+ // When listing buckets, the callback is called just once for all of them.
2059+ //
2060+ // dir should be "" to list the root, and should not have
2061+ // trailing slashes.
2062+ //
2063+ // This should return ErrDirNotFound if the directory isn't found.
2064+ func (f * Fs ) ListCB (ctx context.Context , dir string , cb fs.ListCBCallback ) error {
2065+ bucket , directory := f .split (dir )
2066+ if bucket == "" {
2067+ if directory != "" {
2068+ return fs .ErrorListBucketRequired
2069+ }
2070+ entries , err := f .listBuckets (ctx )
2071+ if err != nil {
2072+ return err
2073+ }
2074+ return cb (entries )
2075+ }
2076+ return f .listDir (ctx , bucket , directory , f .rootDirectory , f .rootBucket == "" , cb )
20412077}
20422078
20432079// ListR lists the objects and directories of the Fs starting
0 commit comments