github.com/10XDev/rclone@v1.52.3-0.20200626220027-16af9ab76b2a/fs/operations/operations.go (about)

     1  // Package operations does generic operations on filesystems and objects
     2  package operations
     3  
     4  import (
     5  	"bytes"
     6  	"context"
     7  	"encoding/base64"
     8  	"encoding/csv"
     9  	"encoding/hex"
    10  	"fmt"
    11  	"io"
    12  	"io/ioutil"
    13  	"net/http"
    14  	"path"
    15  	"path/filepath"
    16  	"sort"
    17  	"strconv"
    18  	"strings"
    19  	"sync"
    20  	"sync/atomic"
    21  	"time"
    22  
    23  	"github.com/pkg/errors"
    24  	"github.com/rclone/rclone/fs"
    25  	"github.com/rclone/rclone/fs/accounting"
    26  	"github.com/rclone/rclone/fs/cache"
    27  	"github.com/rclone/rclone/fs/fserrors"
    28  	"github.com/rclone/rclone/fs/fshttp"
    29  	"github.com/rclone/rclone/fs/hash"
    30  	"github.com/rclone/rclone/fs/march"
    31  	"github.com/rclone/rclone/fs/object"
    32  	"github.com/rclone/rclone/fs/walk"
    33  	"github.com/rclone/rclone/lib/random"
    34  	"github.com/rclone/rclone/lib/readers"
    35  	"golang.org/x/sync/errgroup"
    36  )
    37  
    38  // CheckHashes checks the two files to see if they have common
    39  // known hash types and compares them
    40  //
    41  // Returns
    42  //
    43  // equal - which is equality of the hashes
    44  //
    45  // hash - the HashType. This is HashNone if either of the hashes were
    46  // unset or a compatible hash couldn't be found.
    47  //
    48  // err - may return an error which will already have been logged
    49  //
    50  // If an error is returned it will return equal as false
    51  func CheckHashes(ctx context.Context, src fs.ObjectInfo, dst fs.Object) (equal bool, ht hash.Type, err error) {
    52  	common := src.Fs().Hashes().Overlap(dst.Fs().Hashes())
    53  	// fs.Debugf(nil, "Shared hashes: %v", common)
    54  	if common.Count() == 0 {
    55  		return true, hash.None, nil
    56  	}
    57  	equal, ht, _, _, err = checkHashes(ctx, src, dst, common.GetOne())
    58  	return equal, ht, err
    59  }
    60  
    61  // checkHashes does the work of CheckHashes but takes a hash.Type and
    62  // returns the effective hash type used.
    63  func checkHashes(ctx context.Context, src fs.ObjectInfo, dst fs.Object, ht hash.Type) (equal bool, htOut hash.Type, srcHash, dstHash string, err error) {
    64  	// Calculate hashes in parallel
    65  	g, ctx := errgroup.WithContext(ctx)
    66  	g.Go(func() (err error) {
    67  		srcHash, err = src.Hash(ctx, ht)
    68  		if err != nil {
    69  			err = fs.CountError(err)
    70  			fs.Errorf(src, "Failed to calculate src hash: %v", err)
    71  		}
    72  		return err
    73  	})
    74  	g.Go(func() (err error) {
    75  		dstHash, err = dst.Hash(ctx, ht)
    76  		if err != nil {
    77  			err = fs.CountError(err)
    78  			fs.Errorf(dst, "Failed to calculate dst hash: %v", err)
    79  		}
    80  		return err
    81  	})
    82  	err = g.Wait()
    83  	if err != nil {
    84  		return false, ht, srcHash, dstHash, err
    85  	}
    86  	if srcHash == "" {
    87  		return true, hash.None, srcHash, dstHash, nil
    88  	}
    89  	if dstHash == "" {
    90  		return true, hash.None, srcHash, dstHash, nil
    91  	}
    92  	if srcHash != dstHash {
    93  		fs.Debugf(src, "%v = %s (%v)", ht, srcHash, src.Fs())
    94  		fs.Debugf(dst, "%v = %s (%v)", ht, dstHash, dst.Fs())
    95  	} else {
    96  		fs.Debugf(src, "%v = %s OK", ht, srcHash)
    97  	}
    98  	return srcHash == dstHash, ht, srcHash, dstHash, nil
    99  }
   100  
   101  // Equal checks to see if the src and dst objects are equal by looking at
   102  // size, mtime and hash
   103  //
   104  // If the src and dst size are different then it is considered to be
   105  // not equal.  If --size-only is in effect then this is the only check
   106  // that is done.  If --ignore-size is in effect then this check is
   107  // skipped and the files are considered the same size.
   108  //
   109  // If the size is the same and the mtime is the same then it is
   110  // considered to be equal.  This check is skipped if using --checksum.
   111  //
   112  // If the size is the same and mtime is different, unreadable or
   113  // --checksum is set and the hash is the same then the file is
   114  // considered to be equal.  In this case the mtime on the dst is
   115  // updated if --checksum is not set.
   116  //
   117  // Otherwise the file is considered to be not equal including if there
   118  // were errors reading info.
   119  func Equal(ctx context.Context, src fs.ObjectInfo, dst fs.Object) bool {
   120  	return equal(ctx, src, dst, defaultEqualOpt())
   121  }
   122  
   123  // sizeDiffers compare the size of src and dst taking into account the
   124  // various ways of ignoring sizes
   125  func sizeDiffers(src, dst fs.ObjectInfo) bool {
   126  	if fs.Config.IgnoreSize || src.Size() < 0 || dst.Size() < 0 {
   127  		return false
   128  	}
   129  	return src.Size() != dst.Size()
   130  }
   131  
   132  var checksumWarning sync.Once
   133  
   134  // options for equal function()
   135  type equalOpt struct {
   136  	sizeOnly          bool // if set only check size
   137  	checkSum          bool // if set check checksum+size instead of modtime+size
   138  	updateModTime     bool // if set update the modtime if hashes identical and checking with modtime+size
   139  	forceModTimeMatch bool // if set assume modtimes match
   140  }
   141  
   142  // default set of options for equal()
   143  func defaultEqualOpt() equalOpt {
   144  	return equalOpt{
   145  		sizeOnly:          fs.Config.SizeOnly,
   146  		checkSum:          fs.Config.CheckSum,
   147  		updateModTime:     !fs.Config.NoUpdateModTime,
   148  		forceModTimeMatch: false,
   149  	}
   150  }
   151  
   152  func equal(ctx context.Context, src fs.ObjectInfo, dst fs.Object, opt equalOpt) bool {
   153  	if sizeDiffers(src, dst) {
   154  		fs.Debugf(src, "Sizes differ (src %d vs dst %d)", src.Size(), dst.Size())
   155  		return false
   156  	}
   157  	if opt.sizeOnly {
   158  		fs.Debugf(src, "Sizes identical")
   159  		return true
   160  	}
   161  
   162  	// Assert: Size is equal or being ignored
   163  
   164  	// If checking checksum and not modtime
   165  	if opt.checkSum {
   166  		// Check the hash
   167  		same, ht, _ := CheckHashes(ctx, src, dst)
   168  		if !same {
   169  			fs.Debugf(src, "%v differ", ht)
   170  			return false
   171  		}
   172  		if ht == hash.None {
   173  			checksumWarning.Do(func() {
   174  				fs.Logf(dst.Fs(), "--checksum is in use but the source and destination have no hashes in common; falling back to --size-only")
   175  			})
   176  			fs.Debugf(src, "Size of src and dst objects identical")
   177  		} else {
   178  			fs.Debugf(src, "Size and %v of src and dst objects identical", ht)
   179  		}
   180  		return true
   181  	}
   182  
   183  	srcModTime := src.ModTime(ctx)
   184  	if !opt.forceModTimeMatch {
   185  		// Sizes the same so check the mtime
   186  		modifyWindow := fs.GetModifyWindow(src.Fs(), dst.Fs())
   187  		if modifyWindow == fs.ModTimeNotSupported {
   188  			fs.Debugf(src, "Sizes identical")
   189  			return true
   190  		}
   191  		dstModTime := dst.ModTime(ctx)
   192  		dt := dstModTime.Sub(srcModTime)
   193  		if dt < modifyWindow && dt > -modifyWindow {
   194  			fs.Debugf(src, "Size and modification time the same (differ by %s, within tolerance %s)", dt, modifyWindow)
   195  			return true
   196  		}
   197  
   198  		fs.Debugf(src, "Modification times differ by %s: %v, %v", dt, srcModTime, dstModTime)
   199  	}
   200  
   201  	// Check if the hashes are the same
   202  	same, ht, _ := CheckHashes(ctx, src, dst)
   203  	if !same {
   204  		fs.Debugf(src, "%v differ", ht)
   205  		return false
   206  	}
   207  	if ht == hash.None {
   208  		// if couldn't check hash, return that they differ
   209  		return false
   210  	}
   211  
   212  	// mod time differs but hash is the same to reset mod time if required
   213  	if opt.updateModTime {
   214  		if fs.Config.DryRun {
   215  			fs.Logf(src, "Not updating modification time as --dry-run")
   216  		} else {
   217  			// Size and hash the same but mtime different
   218  			// Error if objects are treated as immutable
   219  			if fs.Config.Immutable {
   220  				fs.Errorf(dst, "StartedAt mismatch between immutable objects")
   221  				return false
   222  			}
   223  			// Update the mtime of the dst object here
   224  			err := dst.SetModTime(ctx, srcModTime)
   225  			if err == fs.ErrorCantSetModTime {
   226  				fs.Debugf(dst, "src and dst identical but can't set mod time without re-uploading")
   227  				return false
   228  			} else if err == fs.ErrorCantSetModTimeWithoutDelete {
   229  				fs.Debugf(dst, "src and dst identical but can't set mod time without deleting and re-uploading")
   230  				// Remove the file if BackupDir isn't set.  If BackupDir is set we would rather have the old file
   231  				// put in the BackupDir than deleted which is what will happen if we don't delete it.
   232  				if fs.Config.BackupDir == "" {
   233  					err = dst.Remove(ctx)
   234  					if err != nil {
   235  						fs.Errorf(dst, "failed to delete before re-upload: %v", err)
   236  					}
   237  				}
   238  				return false
   239  			} else if err != nil {
   240  				err = fs.CountError(err)
   241  				fs.Errorf(dst, "Failed to set modification time: %v", err)
   242  			} else {
   243  				fs.Infof(src, "Updated modification time in destination")
   244  			}
   245  		}
   246  	}
   247  	return true
   248  }
   249  
   250  // Used to remove a failed copy
   251  //
   252  // Returns whether the file was successfully removed or not
   253  func removeFailedCopy(ctx context.Context, dst fs.Object) bool {
   254  	if dst == nil {
   255  		return false
   256  	}
   257  	fs.Infof(dst, "Removing failed copy")
   258  	removeErr := dst.Remove(ctx)
   259  	if removeErr != nil {
   260  		fs.Infof(dst, "Failed to remove failed copy: %s", removeErr)
   261  		return false
   262  	}
   263  	return true
   264  }
   265  
   266  // OverrideRemote is a wrapper to override the Remote for an
   267  // ObjectInfo
   268  type OverrideRemote struct {
   269  	fs.ObjectInfo
   270  	remote string
   271  }
   272  
   273  // NewOverrideRemote returns an OverrideRemoteObject which will
   274  // return the remote specified
   275  func NewOverrideRemote(oi fs.ObjectInfo, remote string) *OverrideRemote {
   276  	return &OverrideRemote{
   277  		ObjectInfo: oi,
   278  		remote:     remote,
   279  	}
   280  }
   281  
   282  // Remote returns the overridden remote name
   283  func (o *OverrideRemote) Remote() string {
   284  	return o.remote
   285  }
   286  
   287  // MimeType returns the mime type of the underlying object or "" if it
   288  // can't be worked out
   289  func (o *OverrideRemote) MimeType(ctx context.Context) string {
   290  	if do, ok := o.ObjectInfo.(fs.MimeTyper); ok {
   291  		return do.MimeType(ctx)
   292  	}
   293  	return ""
   294  }
   295  
   296  // ID returns the ID of the Object if known, or "" if not
   297  func (o *OverrideRemote) ID() string {
   298  	if do, ok := o.ObjectInfo.(fs.IDer); ok {
   299  		return do.ID()
   300  	}
   301  	return ""
   302  }
   303  
   304  // UnWrap returns the Object that this Object is wrapping or nil if it
   305  // isn't wrapping anything
   306  func (o *OverrideRemote) UnWrap() fs.Object {
   307  	if o, ok := o.ObjectInfo.(fs.Object); ok {
   308  		return o
   309  	}
   310  	return nil
   311  }
   312  
   313  // GetTier returns storage tier or class of the Object
   314  func (o *OverrideRemote) GetTier() string {
   315  	if do, ok := o.ObjectInfo.(fs.GetTierer); ok {
   316  		return do.GetTier()
   317  	}
   318  	return ""
   319  }
   320  
   321  // Check all optional interfaces satisfied
   322  var _ fs.FullObjectInfo = (*OverrideRemote)(nil)
   323  
   324  // CommonHash returns a single hash.Type and a HashOption with that
   325  // type which is in common between the two fs.Fs.
   326  func CommonHash(fa, fb fs.Info) (hash.Type, *fs.HashesOption) {
   327  	// work out which hash to use - limit to 1 hash in common
   328  	var common hash.Set
   329  	hashType := hash.None
   330  	if !fs.Config.IgnoreChecksum {
   331  		common = fb.Hashes().Overlap(fa.Hashes())
   332  		if common.Count() > 0 {
   333  			hashType = common.GetOne()
   334  			common = hash.Set(hashType)
   335  		}
   336  	}
   337  	return hashType, &fs.HashesOption{Hashes: common}
   338  }
   339  
   340  // Copy src object to dst or f if nil.  If dst is nil then it uses
   341  // remote as the name of the new object.
   342  //
   343  // It returns the destination object if possible.  Note that this may
   344  // be nil.
   345  func Copy(ctx context.Context, f fs.Fs, dst fs.Object, remote string, src fs.Object) (newDst fs.Object, err error) {
   346  	tr := accounting.Stats(ctx).NewTransfer(src)
   347  	defer func() {
   348  		tr.Done(err)
   349  	}()
   350  	newDst = dst
   351  	if fs.Config.DryRun {
   352  		fs.Logf(src, "Not copying as --dry-run")
   353  		return newDst, nil
   354  	}
   355  	maxTries := fs.Config.LowLevelRetries
   356  	tries := 0
   357  	doUpdate := dst != nil
   358  	hashType, hashOption := CommonHash(f, src.Fs())
   359  
   360  	var actionTaken string
   361  	for {
   362  		// Try server side copy first - if has optional interface and
   363  		// is same underlying remote
   364  		actionTaken = "Copied (server side copy)"
   365  		if fs.Config.MaxTransfer >= 0 && (accounting.Stats(ctx).GetBytes() >= int64(fs.Config.MaxTransfer) ||
   366  			(fs.Config.CutoffMode == fs.CutoffModeCautious && accounting.Stats(ctx).GetBytesWithPending()+src.Size() >= int64(fs.Config.MaxTransfer))) {
   367  			return nil, accounting.ErrorMaxTransferLimitReachedFatal
   368  		}
   369  		if doCopy := f.Features().Copy; doCopy != nil && (SameConfig(src.Fs(), f) || (SameRemoteType(src.Fs(), f) && f.Features().ServerSideAcrossConfigs)) {
   370  			in := tr.Account(nil) // account the transfer
   371  			in.ServerSideCopyStart()
   372  			newDst, err = doCopy(ctx, src, remote)
   373  			if err == nil {
   374  				dst = newDst
   375  				in.ServerSideCopyEnd(dst.Size()) // account the bytes for the server side transfer
   376  				err = in.Close()
   377  			} else {
   378  				_ = in.Close()
   379  			}
   380  			if err == fs.ErrorCantCopy {
   381  				tr.Reset() // skip incomplete accounting - will be overwritten by the manual copy below
   382  			}
   383  		} else {
   384  			err = fs.ErrorCantCopy
   385  		}
   386  		// If can't server side copy, do it manually
   387  		if err == fs.ErrorCantCopy {
   388  			if doMultiThreadCopy(f, src) {
   389  				// Number of streams proportional to size
   390  				streams := src.Size() / int64(fs.Config.MultiThreadCutoff)
   391  				// With maximum
   392  				if streams > int64(fs.Config.MultiThreadStreams) {
   393  					streams = int64(fs.Config.MultiThreadStreams)
   394  				}
   395  				if streams < 2 {
   396  					streams = 2
   397  				}
   398  				dst, err = multiThreadCopy(ctx, f, remote, src, int(streams), tr)
   399  				if doUpdate {
   400  					actionTaken = "Multi-thread Copied (replaced existing)"
   401  				} else {
   402  					actionTaken = "Multi-thread Copied (new)"
   403  				}
   404  			} else {
   405  				var in0 io.ReadCloser
   406  				options := []fs.OpenOption{hashOption}
   407  				for _, option := range fs.Config.DownloadHeaders {
   408  					options = append(options, option)
   409  				}
   410  				in0, err = NewReOpen(ctx, src, fs.Config.LowLevelRetries, options...)
   411  				if err != nil {
   412  					err = errors.Wrap(err, "failed to open source object")
   413  				} else {
   414  					if src.Size() == -1 {
   415  						// -1 indicates unknown size. Use Rcat to handle both remotes supporting and not supporting PutStream.
   416  						if doUpdate {
   417  							actionTaken = "Copied (Rcat, replaced existing)"
   418  						} else {
   419  							actionTaken = "Copied (Rcat, new)"
   420  						}
   421  						// NB Rcat closes in0
   422  						dst, err = Rcat(ctx, f, remote, in0, src.ModTime(ctx))
   423  						newDst = dst
   424  					} else {
   425  						in := tr.Account(in0).WithBuffer() // account and buffer the transfer
   426  						var wrappedSrc fs.ObjectInfo = src
   427  						// We try to pass the original object if possible
   428  						if src.Remote() != remote {
   429  							wrappedSrc = NewOverrideRemote(src, remote)
   430  						}
   431  						options := []fs.OpenOption{hashOption}
   432  						for _, option := range fs.Config.UploadHeaders {
   433  							options = append(options, option)
   434  						}
   435  						if doUpdate {
   436  							actionTaken = "Copied (replaced existing)"
   437  							err = dst.Update(ctx, in, wrappedSrc, options...)
   438  						} else {
   439  							actionTaken = "Copied (new)"
   440  							dst, err = f.Put(ctx, in, wrappedSrc, options...)
   441  						}
   442  						closeErr := in.Close()
   443  						if err == nil {
   444  							newDst = dst
   445  							err = closeErr
   446  						}
   447  					}
   448  				}
   449  			}
   450  		}
   451  		tries++
   452  		if tries >= maxTries {
   453  			break
   454  		}
   455  		// Retry if err returned a retry error
   456  		if fserrors.IsRetryError(err) || fserrors.ShouldRetry(err) {
   457  			fs.Debugf(src, "Received error: %v - low level retry %d/%d", err, tries, maxTries)
   458  			tr.Reset() // skip incomplete accounting - will be overwritten by retry
   459  			continue
   460  		}
   461  		// otherwise finish
   462  		break
   463  	}
   464  	if err != nil {
   465  		err = fs.CountError(err)
   466  		fs.Errorf(src, "Failed to copy: %v", err)
   467  		return newDst, err
   468  	}
   469  
   470  	// Verify sizes are the same after transfer
   471  	if sizeDiffers(src, dst) {
   472  		err = errors.Errorf("corrupted on transfer: sizes differ %d vs %d", src.Size(), dst.Size())
   473  		fs.Errorf(dst, "%v", err)
   474  		err = fs.CountError(err)
   475  		removeFailedCopy(ctx, dst)
   476  		return newDst, err
   477  	}
   478  
   479  	// Verify hashes are the same after transfer - ignoring blank hashes
   480  	if hashType != hash.None {
   481  		// checkHashes has logged and counted errors
   482  		equal, _, srcSum, dstSum, _ := checkHashes(ctx, src, dst, hashType)
   483  		if !equal {
   484  			err = errors.Errorf("corrupted on transfer: %v hash differ %q vs %q", hashType, srcSum, dstSum)
   485  			fs.Errorf(dst, "%v", err)
   486  			err = fs.CountError(err)
   487  			removeFailedCopy(ctx, dst)
   488  			return newDst, err
   489  		}
   490  	}
   491  
   492  	fs.Infof(src, actionTaken)
   493  	return newDst, err
   494  }
   495  
   496  // SameObject returns true if src and dst could be pointing to the
   497  // same object.
   498  func SameObject(src, dst fs.Object) bool {
   499  	if !SameConfig(src.Fs(), dst.Fs()) {
   500  		return false
   501  	}
   502  	srcPath := path.Join(src.Fs().Root(), src.Remote())
   503  	dstPath := path.Join(dst.Fs().Root(), dst.Remote())
   504  	if dst.Fs().Features().CaseInsensitive {
   505  		srcPath = strings.ToLower(srcPath)
   506  		dstPath = strings.ToLower(dstPath)
   507  	}
   508  	return srcPath == dstPath
   509  }
   510  
   511  // Move src object to dst or fdst if nil.  If dst is nil then it uses
   512  // remote as the name of the new object.
   513  //
   514  // Note that you must check the destination does not exist before
   515  // calling this and pass it as dst.  If you pass dst=nil and the
   516  // destination does exist then this may create duplicates or return
   517  // errors.
   518  //
   519  // It returns the destination object if possible.  Note that this may
   520  // be nil.
   521  func Move(ctx context.Context, fdst fs.Fs, dst fs.Object, remote string, src fs.Object) (newDst fs.Object, err error) {
   522  	tr := accounting.Stats(ctx).NewCheckingTransfer(src)
   523  	defer func() {
   524  		if err == nil {
   525  			accounting.Stats(ctx).Renames(1)
   526  		}
   527  		tr.Done(err)
   528  	}()
   529  	newDst = dst
   530  	if fs.Config.DryRun {
   531  		fs.Logf(src, "Not moving as --dry-run")
   532  		return newDst, nil
   533  	}
   534  	// See if we have Move available
   535  	if doMove := fdst.Features().Move; doMove != nil && (SameConfig(src.Fs(), fdst) || (SameRemoteType(src.Fs(), fdst) && fdst.Features().ServerSideAcrossConfigs)) {
   536  		// Delete destination if it exists and is not the same file as src (could be same file while seemingly different if the remote is case insensitive)
   537  		if dst != nil && !SameObject(src, dst) {
   538  			err = DeleteFile(ctx, dst)
   539  			if err != nil {
   540  				return newDst, err
   541  			}
   542  		}
   543  		// Move dst <- src
   544  		newDst, err = doMove(ctx, src, remote)
   545  		switch err {
   546  		case nil:
   547  			fs.Infof(src, "Moved (server side)")
   548  			return newDst, nil
   549  		case fs.ErrorCantMove:
   550  			fs.Debugf(src, "Can't move, switching to copy")
   551  		default:
   552  			err = fs.CountError(err)
   553  			fs.Errorf(src, "Couldn't move: %v", err)
   554  			return newDst, err
   555  		}
   556  	}
   557  	// Move not found or didn't work so copy dst <- src
   558  	newDst, err = Copy(ctx, fdst, dst, remote, src)
   559  	if err != nil {
   560  		fs.Errorf(src, "Not deleting source as copy failed: %v", err)
   561  		return newDst, err
   562  	}
   563  	// Delete src if no error on copy
   564  	return newDst, DeleteFile(ctx, src)
   565  }
   566  
   567  // CanServerSideMove returns true if fdst support server side moves or
   568  // server side copies
   569  //
   570  // Some remotes simulate rename by server-side copy and delete, so include
   571  // remotes that implements either Mover or Copier.
   572  func CanServerSideMove(fdst fs.Fs) bool {
   573  	canMove := fdst.Features().Move != nil
   574  	canCopy := fdst.Features().Copy != nil
   575  	return canMove || canCopy
   576  }
   577  
   578  // SuffixName adds the current --suffix to the remote, obeying
   579  // --suffix-keep-extension if set
   580  func SuffixName(remote string) string {
   581  	if fs.Config.Suffix == "" {
   582  		return remote
   583  	}
   584  	if fs.Config.SuffixKeepExtension {
   585  		ext := path.Ext(remote)
   586  		base := remote[:len(remote)-len(ext)]
   587  		return base + fs.Config.Suffix + ext
   588  	}
   589  	return remote + fs.Config.Suffix
   590  }
   591  
   592  // DeleteFileWithBackupDir deletes a single file respecting --dry-run
   593  // and accumulating stats and errors.
   594  //
   595  // If backupDir is set then it moves the file to there instead of
   596  // deleting
   597  func DeleteFileWithBackupDir(ctx context.Context, dst fs.Object, backupDir fs.Fs) (err error) {
   598  	tr := accounting.Stats(ctx).NewCheckingTransfer(dst)
   599  	defer func() {
   600  		tr.Done(err)
   601  	}()
   602  	numDeletes := accounting.Stats(ctx).Deletes(1)
   603  	if fs.Config.MaxDelete != -1 && numDeletes > fs.Config.MaxDelete {
   604  		return fserrors.FatalError(errors.New("--max-delete threshold reached"))
   605  	}
   606  	action, actioned, actioning := "delete", "Deleted", "deleting"
   607  	if backupDir != nil {
   608  		action, actioned, actioning = "move into backup dir", "Moved into backup dir", "moving into backup dir"
   609  	}
   610  	if fs.Config.DryRun {
   611  		fs.Logf(dst, "Not %s as --dry-run", actioning)
   612  	} else if backupDir != nil {
   613  		err = MoveBackupDir(ctx, backupDir, dst)
   614  	} else {
   615  		err = dst.Remove(ctx)
   616  	}
   617  	if err != nil {
   618  		fs.Errorf(dst, "Couldn't %s: %v", action, err)
   619  		err = fs.CountError(err)
   620  	} else if !fs.Config.DryRun {
   621  		fs.Infof(dst, actioned)
   622  	}
   623  	return err
   624  }
   625  
   626  // DeleteFile deletes a single file respecting --dry-run and accumulating stats and errors.
   627  //
   628  // If useBackupDir is set and --backup-dir is in effect then it moves
   629  // the file to there instead of deleting
   630  func DeleteFile(ctx context.Context, dst fs.Object) (err error) {
   631  	return DeleteFileWithBackupDir(ctx, dst, nil)
   632  }
   633  
   634  // DeleteFilesWithBackupDir removes all the files passed in the
   635  // channel
   636  //
   637  // If backupDir is set the files will be placed into that directory
   638  // instead of being deleted.
   639  func DeleteFilesWithBackupDir(ctx context.Context, toBeDeleted fs.ObjectsChan, backupDir fs.Fs) error {
   640  	var wg sync.WaitGroup
   641  	wg.Add(fs.Config.Transfers)
   642  	var errorCount int32
   643  	var fatalErrorCount int32
   644  
   645  	for i := 0; i < fs.Config.Transfers; i++ {
   646  		go func() {
   647  			defer wg.Done()
   648  			for dst := range toBeDeleted {
   649  				err := DeleteFileWithBackupDir(ctx, dst, backupDir)
   650  				if err != nil {
   651  					atomic.AddInt32(&errorCount, 1)
   652  					if fserrors.IsFatalError(err) {
   653  						fs.Errorf(nil, "Got fatal error on delete: %s", err)
   654  						atomic.AddInt32(&fatalErrorCount, 1)
   655  						return
   656  					}
   657  				}
   658  			}
   659  		}()
   660  	}
   661  	fs.Debugf(nil, "Waiting for deletions to finish")
   662  	wg.Wait()
   663  	if errorCount > 0 {
   664  		err := errors.Errorf("failed to delete %d files", errorCount)
   665  		if fatalErrorCount > 0 {
   666  			return fserrors.FatalError(err)
   667  		}
   668  		return err
   669  	}
   670  	return nil
   671  }
   672  
   673  // DeleteFiles removes all the files passed in the channel
   674  func DeleteFiles(ctx context.Context, toBeDeleted fs.ObjectsChan) error {
   675  	return DeleteFilesWithBackupDir(ctx, toBeDeleted, nil)
   676  }
   677  
   678  // SameRemoteType returns true if fdst and fsrc are the same type
   679  func SameRemoteType(fdst, fsrc fs.Info) bool {
   680  	return fmt.Sprintf("%T", fdst) == fmt.Sprintf("%T", fsrc)
   681  }
   682  
   683  // SameConfig returns true if fdst and fsrc are using the same config
   684  // file entry
   685  func SameConfig(fdst, fsrc fs.Info) bool {
   686  	return fdst.Name() == fsrc.Name()
   687  }
   688  
   689  // Same returns true if fdst and fsrc point to the same underlying Fs
   690  func Same(fdst, fsrc fs.Info) bool {
   691  	return SameConfig(fdst, fsrc) && strings.Trim(fdst.Root(), "/") == strings.Trim(fsrc.Root(), "/")
   692  }
   693  
   694  // fixRoot returns the Root with a trailing / if not empty. It is
   695  // aware of case insensitive filesystems.
   696  func fixRoot(f fs.Info) string {
   697  	s := strings.Trim(filepath.ToSlash(f.Root()), "/")
   698  	if s != "" {
   699  		s += "/"
   700  	}
   701  	if f.Features().CaseInsensitive {
   702  		s = strings.ToLower(s)
   703  	}
   704  	return s
   705  }
   706  
   707  // Overlapping returns true if fdst and fsrc point to the same
   708  // underlying Fs and they overlap.
   709  func Overlapping(fdst, fsrc fs.Info) bool {
   710  	if !SameConfig(fdst, fsrc) {
   711  		return false
   712  	}
   713  	fdstRoot := fixRoot(fdst)
   714  	fsrcRoot := fixRoot(fsrc)
   715  	return strings.HasPrefix(fdstRoot, fsrcRoot) || strings.HasPrefix(fsrcRoot, fdstRoot)
   716  }
   717  
   718  // SameDir returns true if fdst and fsrc point to the same
   719  // underlying Fs and they are the same directory.
   720  func SameDir(fdst, fsrc fs.Info) bool {
   721  	if !SameConfig(fdst, fsrc) {
   722  		return false
   723  	}
   724  	fdstRoot := fixRoot(fdst)
   725  	fsrcRoot := fixRoot(fsrc)
   726  	return fdstRoot == fsrcRoot
   727  }
   728  
   729  // checkIdentical checks to see if dst and src are identical
   730  //
   731  // it returns true if differences were found
   732  // it also returns whether it couldn't be hashed
   733  func checkIdentical(ctx context.Context, dst, src fs.Object) (differ bool, noHash bool) {
   734  	same, ht, err := CheckHashes(ctx, src, dst)
   735  	if err != nil {
   736  		// CheckHashes will log and count errors
   737  		return true, false
   738  	}
   739  	if ht == hash.None {
   740  		return false, true
   741  	}
   742  	if !same {
   743  		err = errors.Errorf("%v differ", ht)
   744  		fs.Errorf(src, "%v", err)
   745  		_ = fs.CountError(err)
   746  		return true, false
   747  	}
   748  	return false, false
   749  }
   750  
   751  // checkFn is the type of the checking function used in CheckFn()
   752  type checkFn func(ctx context.Context, a, b fs.Object) (differ bool, noHash bool)
   753  
   754  // checkMarch is used to march over two Fses in the same way as
   755  // sync/copy
   756  type checkMarch struct {
   757  	fdst, fsrc      fs.Fs
   758  	check           checkFn
   759  	oneway          bool
   760  	differences     int32
   761  	noHashes        int32
   762  	srcFilesMissing int32
   763  	dstFilesMissing int32
   764  	matches         int32
   765  }
   766  
   767  // DstOnly have an object which is in the destination only
   768  func (c *checkMarch) DstOnly(dst fs.DirEntry) (recurse bool) {
   769  	switch dst.(type) {
   770  	case fs.Object:
   771  		if c.oneway {
   772  			return false
   773  		}
   774  		err := errors.Errorf("File not in %v", c.fsrc)
   775  		fs.Errorf(dst, "%v", err)
   776  		_ = fs.CountError(err)
   777  		atomic.AddInt32(&c.differences, 1)
   778  		atomic.AddInt32(&c.srcFilesMissing, 1)
   779  	case fs.Directory:
   780  		// Do the same thing to the entire contents of the directory
   781  		if c.oneway {
   782  			return false
   783  		}
   784  		return true
   785  	default:
   786  		panic("Bad object in DirEntries")
   787  	}
   788  	return false
   789  }
   790  
   791  // SrcOnly have an object which is in the source only
   792  func (c *checkMarch) SrcOnly(src fs.DirEntry) (recurse bool) {
   793  	switch src.(type) {
   794  	case fs.Object:
   795  		err := errors.Errorf("File not in %v", c.fdst)
   796  		fs.Errorf(src, "%v", err)
   797  		_ = fs.CountError(err)
   798  		atomic.AddInt32(&c.differences, 1)
   799  		atomic.AddInt32(&c.dstFilesMissing, 1)
   800  	case fs.Directory:
   801  		// Do the same thing to the entire contents of the directory
   802  		return true
   803  	default:
   804  		panic("Bad object in DirEntries")
   805  	}
   806  	return false
   807  }
   808  
   809  // check to see if two objects are identical using the check function
   810  func (c *checkMarch) checkIdentical(ctx context.Context, dst, src fs.Object) (differ bool, noHash bool) {
   811  	var err error
   812  	tr := accounting.Stats(ctx).NewCheckingTransfer(src)
   813  	defer func() {
   814  		tr.Done(err)
   815  	}()
   816  	if sizeDiffers(src, dst) {
   817  		err = errors.Errorf("Sizes differ")
   818  		fs.Errorf(src, "%v", err)
   819  		return true, false
   820  	}
   821  	if fs.Config.SizeOnly {
   822  		return false, false
   823  	}
   824  	return c.check(ctx, dst, src)
   825  }
   826  
   827  // Match is called when src and dst are present, so sync src to dst
   828  func (c *checkMarch) Match(ctx context.Context, dst, src fs.DirEntry) (recurse bool) {
   829  	switch srcX := src.(type) {
   830  	case fs.Object:
   831  		dstX, ok := dst.(fs.Object)
   832  		if ok {
   833  			differ, noHash := c.checkIdentical(ctx, dstX, srcX)
   834  			if differ {
   835  				atomic.AddInt32(&c.differences, 1)
   836  			} else {
   837  				atomic.AddInt32(&c.matches, 1)
   838  				if noHash {
   839  					atomic.AddInt32(&c.noHashes, 1)
   840  					fs.Debugf(dstX, "OK - could not check hash")
   841  				} else {
   842  					fs.Debugf(dstX, "OK")
   843  				}
   844  			}
   845  		} else {
   846  			err := errors.Errorf("is file on %v but directory on %v", c.fsrc, c.fdst)
   847  			fs.Errorf(src, "%v", err)
   848  			_ = fs.CountError(err)
   849  			atomic.AddInt32(&c.differences, 1)
   850  			atomic.AddInt32(&c.dstFilesMissing, 1)
   851  		}
   852  	case fs.Directory:
   853  		// Do the same thing to the entire contents of the directory
   854  		_, ok := dst.(fs.Directory)
   855  		if ok {
   856  			return true
   857  		}
   858  		err := errors.Errorf("is file on %v but directory on %v", c.fdst, c.fsrc)
   859  		fs.Errorf(dst, "%v", err)
   860  		_ = fs.CountError(err)
   861  		atomic.AddInt32(&c.differences, 1)
   862  		atomic.AddInt32(&c.srcFilesMissing, 1)
   863  
   864  	default:
   865  		panic("Bad object in DirEntries")
   866  	}
   867  	return false
   868  }
   869  
   870  // CheckFn checks the files in fsrc and fdst according to Size and
   871  // hash using checkFunction on each file to check the hashes.
   872  //
   873  // checkFunction sees if dst and src are identical
   874  //
   875  // it returns true if differences were found
   876  // it also returns whether it couldn't be hashed
   877  func CheckFn(ctx context.Context, fdst, fsrc fs.Fs, check checkFn, oneway bool) error {
   878  	c := &checkMarch{
   879  		fdst:   fdst,
   880  		fsrc:   fsrc,
   881  		check:  check,
   882  		oneway: oneway,
   883  	}
   884  
   885  	// set up a march over fdst and fsrc
   886  	m := &march.March{
   887  		Ctx:      ctx,
   888  		Fdst:     fdst,
   889  		Fsrc:     fsrc,
   890  		Dir:      "",
   891  		Callback: c,
   892  	}
   893  	fs.Debugf(fdst, "Waiting for checks to finish")
   894  	err := m.Run()
   895  
   896  	if c.dstFilesMissing > 0 {
   897  		fs.Logf(fdst, "%d files missing", c.dstFilesMissing)
   898  	}
   899  	if c.srcFilesMissing > 0 {
   900  		fs.Logf(fsrc, "%d files missing", c.srcFilesMissing)
   901  	}
   902  
   903  	fs.Logf(fdst, "%d differences found", c.differences)
   904  	if errs := accounting.Stats(ctx).GetErrors(); errs > 0 {
   905  		fs.Logf(fdst, "%d errors while checking", errs)
   906  	}
   907  	if c.noHashes > 0 {
   908  		fs.Logf(fdst, "%d hashes could not be checked", c.noHashes)
   909  	}
   910  	if c.matches > 0 {
   911  		fs.Logf(fdst, "%d matching files", c.matches)
   912  	}
   913  	if c.differences > 0 {
   914  		return errors.Errorf("%d differences found", c.differences)
   915  	}
   916  	return err
   917  }
   918  
   919  // Check the files in fsrc and fdst according to Size and hash
   920  func Check(ctx context.Context, fdst, fsrc fs.Fs, oneway bool) error {
   921  	return CheckFn(ctx, fdst, fsrc, checkIdentical, oneway)
   922  }
   923  
   924  // CheckEqualReaders checks to see if in1 and in2 have the same
   925  // content when read.
   926  //
   927  // it returns true if differences were found
   928  func CheckEqualReaders(in1, in2 io.Reader) (differ bool, err error) {
   929  	const bufSize = 64 * 1024
   930  	buf1 := make([]byte, bufSize)
   931  	buf2 := make([]byte, bufSize)
   932  	for {
   933  		n1, err1 := readers.ReadFill(in1, buf1)
   934  		n2, err2 := readers.ReadFill(in2, buf2)
   935  		// check errors
   936  		if err1 != nil && err1 != io.EOF {
   937  			return true, err1
   938  		} else if err2 != nil && err2 != io.EOF {
   939  			return true, err2
   940  		}
   941  		// err1 && err2 are nil or io.EOF here
   942  		// process the data
   943  		if n1 != n2 || !bytes.Equal(buf1[:n1], buf2[:n2]) {
   944  			return true, nil
   945  		}
   946  		// if both streams finished the we have finished
   947  		if err1 == io.EOF && err2 == io.EOF {
   948  			break
   949  		}
   950  	}
   951  	return false, nil
   952  }
   953  
   954  // CheckIdentical checks to see if dst and src are identical by
   955  // reading all their bytes if necessary.
   956  //
   957  // it returns true if differences were found
   958  func CheckIdentical(ctx context.Context, dst, src fs.Object) (differ bool, err error) {
   959  	in1, err := dst.Open(ctx)
   960  	if err != nil {
   961  		return true, errors.Wrapf(err, "failed to open %q", dst)
   962  	}
   963  	tr1 := accounting.Stats(ctx).NewTransfer(dst)
   964  	defer func() {
   965  		tr1.Done(err)
   966  	}()
   967  	in1 = tr1.Account(in1).WithBuffer() // account and buffer the transfer
   968  
   969  	in2, err := src.Open(ctx)
   970  	if err != nil {
   971  		return true, errors.Wrapf(err, "failed to open %q", src)
   972  	}
   973  	tr2 := accounting.Stats(ctx).NewTransfer(dst)
   974  	defer func() {
   975  		tr2.Done(err)
   976  	}()
   977  	in2 = tr2.Account(in2).WithBuffer() // account and buffer the transfer
   978  
   979  	// To assign err variable before defer.
   980  	differ, err = CheckEqualReaders(in1, in2)
   981  	return
   982  }
   983  
   984  // CheckDownload checks the files in fsrc and fdst according to Size
   985  // and the actual contents of the files.
   986  func CheckDownload(ctx context.Context, fdst, fsrc fs.Fs, oneway bool) error {
   987  	check := func(ctx context.Context, a, b fs.Object) (differ bool, noHash bool) {
   988  		differ, err := CheckIdentical(ctx, a, b)
   989  		if err != nil {
   990  			err = fs.CountError(err)
   991  			fs.Errorf(a, "Failed to download: %v", err)
   992  			return true, true
   993  		}
   994  		return differ, false
   995  	}
   996  	return CheckFn(ctx, fdst, fsrc, check, oneway)
   997  }
   998  
   999  // ListFn lists the Fs to the supplied function
  1000  //
  1001  // Lists in parallel which may get them out of order
  1002  func ListFn(ctx context.Context, f fs.Fs, fn func(fs.Object)) error {
  1003  	return walk.ListR(ctx, f, "", false, fs.Config.MaxDepth, walk.ListObjects, func(entries fs.DirEntries) error {
  1004  		entries.ForObject(fn)
  1005  		return nil
  1006  	})
  1007  }
  1008  
  1009  // mutex for synchronized output
  1010  var outMutex sync.Mutex
  1011  
  1012  // Synchronized fmt.Fprintf
  1013  //
  1014  // Ignores errors from Fprintf
  1015  func syncFprintf(w io.Writer, format string, a ...interface{}) {
  1016  	outMutex.Lock()
  1017  	defer outMutex.Unlock()
  1018  	_, _ = fmt.Fprintf(w, format, a...)
  1019  }
  1020  
  1021  // List the Fs to the supplied writer
  1022  //
  1023  // Shows size and path - obeys includes and excludes
  1024  //
  1025  // Lists in parallel which may get them out of order
  1026  func List(ctx context.Context, f fs.Fs, w io.Writer) error {
  1027  	return ListFn(ctx, f, func(o fs.Object) {
  1028  		syncFprintf(w, "%9d %s\n", o.Size(), o.Remote())
  1029  	})
  1030  }
  1031  
  1032  // ListLong lists the Fs to the supplied writer
  1033  //
  1034  // Shows size, mod time and path - obeys includes and excludes
  1035  //
  1036  // Lists in parallel which may get them out of order
  1037  func ListLong(ctx context.Context, f fs.Fs, w io.Writer) error {
  1038  	return ListFn(ctx, f, func(o fs.Object) {
  1039  		tr := accounting.Stats(ctx).NewCheckingTransfer(o)
  1040  		defer func() {
  1041  			tr.Done(nil)
  1042  		}()
  1043  		modTime := o.ModTime(ctx)
  1044  		syncFprintf(w, "%9d %s %s\n", o.Size(), modTime.Local().Format("2006-01-02 15:04:05.000000000"), o.Remote())
  1045  	})
  1046  }
  1047  
  1048  // Md5sum list the Fs to the supplied writer
  1049  //
  1050  // Produces the same output as the md5sum command - obeys includes and
  1051  // excludes
  1052  //
  1053  // Lists in parallel which may get them out of order
  1054  func Md5sum(ctx context.Context, f fs.Fs, w io.Writer) error {
  1055  	return HashLister(ctx, hash.MD5, f, w)
  1056  }
  1057  
  1058  // Sha1sum list the Fs to the supplied writer
  1059  //
  1060  // Obeys includes and excludes
  1061  //
  1062  // Lists in parallel which may get them out of order
  1063  func Sha1sum(ctx context.Context, f fs.Fs, w io.Writer) error {
  1064  	return HashLister(ctx, hash.SHA1, f, w)
  1065  }
  1066  
  1067  // hashSum returns the human readable hash for ht passed in.  This may
  1068  // be UNSUPPORTED or ERROR. If it isn't returning a valid hash it will
  1069  // return an error.
  1070  func hashSum(ctx context.Context, ht hash.Type, o fs.Object) (string, error) {
  1071  	var err error
  1072  	tr := accounting.Stats(ctx).NewCheckingTransfer(o)
  1073  	defer func() {
  1074  		tr.Done(err)
  1075  	}()
  1076  	sum, err := o.Hash(ctx, ht)
  1077  	if err == hash.ErrUnsupported {
  1078  		sum = "UNSUPPORTED"
  1079  	} else if err != nil {
  1080  		fs.Debugf(o, "Failed to read %v: %v", ht, err)
  1081  		sum = "ERROR"
  1082  	}
  1083  	return sum, err
  1084  }
  1085  
  1086  // HashLister does an md5sum equivalent for the hash type passed in
  1087  func HashLister(ctx context.Context, ht hash.Type, f fs.Fs, w io.Writer) error {
  1088  	return ListFn(ctx, f, func(o fs.Object) {
  1089  		sum, _ := hashSum(ctx, ht, o)
  1090  		syncFprintf(w, "%*s  %s\n", hash.Width(ht), sum, o.Remote())
  1091  	})
  1092  }
  1093  
  1094  // HashListerBase64 does an md5sum equivalent for the hash type passed in with base64 encoded
  1095  func HashListerBase64(ctx context.Context, ht hash.Type, f fs.Fs, w io.Writer) error {
  1096  	return ListFn(ctx, f, func(o fs.Object) {
  1097  		sum, err := hashSum(ctx, ht, o)
  1098  		if err == nil {
  1099  			hexBytes, _ := hex.DecodeString(sum)
  1100  			sum = base64.URLEncoding.EncodeToString(hexBytes)
  1101  		}
  1102  		width := base64.URLEncoding.EncodedLen(hash.Width(ht) / 2)
  1103  		syncFprintf(w, "%*s  %s\n", width, sum, o.Remote())
  1104  	})
  1105  }
  1106  
  1107  // Count counts the objects and their sizes in the Fs
  1108  //
  1109  // Obeys includes and excludes
  1110  func Count(ctx context.Context, f fs.Fs) (objects int64, size int64, err error) {
  1111  	err = ListFn(ctx, f, func(o fs.Object) {
  1112  		atomic.AddInt64(&objects, 1)
  1113  		objectSize := o.Size()
  1114  		if objectSize > 0 {
  1115  			atomic.AddInt64(&size, objectSize)
  1116  		}
  1117  	})
  1118  	return
  1119  }
  1120  
  1121  // ConfigMaxDepth returns the depth to use for a recursive or non recursive listing.
  1122  func ConfigMaxDepth(recursive bool) int {
  1123  	depth := fs.Config.MaxDepth
  1124  	if !recursive && depth < 0 {
  1125  		depth = 1
  1126  	}
  1127  	return depth
  1128  }
  1129  
  1130  // ListDir lists the directories/buckets/containers in the Fs to the supplied writer
  1131  func ListDir(ctx context.Context, f fs.Fs, w io.Writer) error {
  1132  	return walk.ListR(ctx, f, "", false, ConfigMaxDepth(false), walk.ListDirs, func(entries fs.DirEntries) error {
  1133  		entries.ForDir(func(dir fs.Directory) {
  1134  			if dir != nil {
  1135  				syncFprintf(w, "%12d %13s %9d %s\n", dir.Size(), dir.ModTime(ctx).Local().Format("2006-01-02 15:04:05"), dir.Items(), dir.Remote())
  1136  			}
  1137  		})
  1138  		return nil
  1139  	})
  1140  }
  1141  
  1142  // Mkdir makes a destination directory or container
  1143  func Mkdir(ctx context.Context, f fs.Fs, dir string) error {
  1144  	if fs.Config.DryRun {
  1145  		fs.Logf(fs.LogDirName(f, dir), "Not making directory as dry run is set")
  1146  		return nil
  1147  	}
  1148  	fs.Debugf(fs.LogDirName(f, dir), "Making directory")
  1149  	err := f.Mkdir(ctx, dir)
  1150  	if err != nil {
  1151  		err = fs.CountError(err)
  1152  		return err
  1153  	}
  1154  	return nil
  1155  }
  1156  
  1157  // TryRmdir removes a container but not if not empty.  It doesn't
  1158  // count errors but may return one.
  1159  func TryRmdir(ctx context.Context, f fs.Fs, dir string) error {
  1160  	if fs.Config.DryRun {
  1161  		fs.Logf(fs.LogDirName(f, dir), "Not deleting as dry run is set")
  1162  		return nil
  1163  	}
  1164  	fs.Debugf(fs.LogDirName(f, dir), "Removing directory")
  1165  	return f.Rmdir(ctx, dir)
  1166  }
  1167  
  1168  // Rmdir removes a container but not if not empty
  1169  func Rmdir(ctx context.Context, f fs.Fs, dir string) error {
  1170  	err := TryRmdir(ctx, f, dir)
  1171  	if err != nil {
  1172  		err = fs.CountError(err)
  1173  		return err
  1174  	}
  1175  	return err
  1176  }
  1177  
  1178  // Purge removes a directory and all of its contents
  1179  func Purge(ctx context.Context, f fs.Fs, dir string) error {
  1180  	doFallbackPurge := true
  1181  	var err error
  1182  	if dir == "" {
  1183  		// FIXME change the Purge interface so it takes a dir - see #1891
  1184  		if doPurge := f.Features().Purge; doPurge != nil {
  1185  			doFallbackPurge = false
  1186  			if fs.Config.DryRun {
  1187  				fs.Logf(f, "Not purging as --dry-run set")
  1188  			} else {
  1189  				err = doPurge(ctx)
  1190  				if err == fs.ErrorCantPurge {
  1191  					doFallbackPurge = true
  1192  				}
  1193  			}
  1194  		}
  1195  	}
  1196  	if doFallbackPurge {
  1197  		// DeleteFiles and Rmdir observe --dry-run
  1198  		err = DeleteFiles(ctx, listToChan(ctx, f, dir))
  1199  		if err != nil {
  1200  			return err
  1201  		}
  1202  		err = Rmdirs(ctx, f, dir, false)
  1203  	}
  1204  	if err != nil {
  1205  		err = fs.CountError(err)
  1206  		return err
  1207  	}
  1208  	return nil
  1209  }
  1210  
  1211  // Delete removes all the contents of a container.  Unlike Purge, it
  1212  // obeys includes and excludes.
  1213  func Delete(ctx context.Context, f fs.Fs) error {
  1214  	delChan := make(fs.ObjectsChan, fs.Config.Transfers)
  1215  	delErr := make(chan error, 1)
  1216  	go func() {
  1217  		delErr <- DeleteFiles(ctx, delChan)
  1218  	}()
  1219  	err := ListFn(ctx, f, func(o fs.Object) {
  1220  		delChan <- o
  1221  	})
  1222  	close(delChan)
  1223  	delError := <-delErr
  1224  	if err == nil {
  1225  		err = delError
  1226  	}
  1227  	return err
  1228  }
  1229  
  1230  // listToChan will transfer all objects in the listing to the output
  1231  //
  1232  // If an error occurs, the error will be logged, and it will close the
  1233  // channel.
  1234  //
  1235  // If the error was ErrorDirNotFound then it will be ignored
  1236  func listToChan(ctx context.Context, f fs.Fs, dir string) fs.ObjectsChan {
  1237  	o := make(fs.ObjectsChan, fs.Config.Checkers)
  1238  	go func() {
  1239  		defer close(o)
  1240  		err := walk.ListR(ctx, f, dir, true, fs.Config.MaxDepth, walk.ListObjects, func(entries fs.DirEntries) error {
  1241  			entries.ForObject(func(obj fs.Object) {
  1242  				o <- obj
  1243  			})
  1244  			return nil
  1245  		})
  1246  		if err != nil && err != fs.ErrorDirNotFound {
  1247  			err = errors.Wrap(err, "failed to list")
  1248  			err = fs.CountError(err)
  1249  			fs.Errorf(nil, "%v", err)
  1250  		}
  1251  	}()
  1252  	return o
  1253  }
  1254  
  1255  // CleanUp removes the trash for the Fs
  1256  func CleanUp(ctx context.Context, f fs.Fs) error {
  1257  	doCleanUp := f.Features().CleanUp
  1258  	if doCleanUp == nil {
  1259  		return errors.Errorf("%v doesn't support cleanup", f)
  1260  	}
  1261  	if fs.Config.DryRun {
  1262  		fs.Logf(f, "Not running cleanup as --dry-run set")
  1263  		return nil
  1264  	}
  1265  	return doCleanUp(ctx)
  1266  }
  1267  
  1268  // wrap a Reader and a Closer together into a ReadCloser
  1269  type readCloser struct {
  1270  	io.Reader
  1271  	io.Closer
  1272  }
  1273  
  1274  // Cat any files to the io.Writer
  1275  //
  1276  // if offset == 0 it will be ignored
  1277  // if offset > 0 then the file will be seeked to that offset
  1278  // if offset < 0 then the file will be seeked that far from the end
  1279  //
  1280  // if count < 0 then it will be ignored
  1281  // if count >= 0 then only that many characters will be output
  1282  func Cat(ctx context.Context, f fs.Fs, w io.Writer, offset, count int64) error {
  1283  	var mu sync.Mutex
  1284  	return ListFn(ctx, f, func(o fs.Object) {
  1285  		var err error
  1286  		tr := accounting.Stats(ctx).NewTransfer(o)
  1287  		defer func() {
  1288  			tr.Done(err)
  1289  		}()
  1290  		opt := fs.RangeOption{Start: offset, End: -1}
  1291  		size := o.Size()
  1292  		if opt.Start < 0 {
  1293  			opt.Start += size
  1294  		}
  1295  		if count >= 0 {
  1296  			opt.End = opt.Start + count - 1
  1297  		}
  1298  		var options []fs.OpenOption
  1299  		if opt.Start > 0 || opt.End >= 0 {
  1300  			options = append(options, &opt)
  1301  		}
  1302  		for _, option := range fs.Config.DownloadHeaders {
  1303  			options = append(options, option)
  1304  		}
  1305  		in, err := o.Open(ctx, options...)
  1306  		if err != nil {
  1307  			err = fs.CountError(err)
  1308  			fs.Errorf(o, "Failed to open: %v", err)
  1309  			return
  1310  		}
  1311  		if count >= 0 {
  1312  			in = &readCloser{Reader: &io.LimitedReader{R: in, N: count}, Closer: in}
  1313  		}
  1314  		in = tr.Account(in).WithBuffer() // account and buffer the transfer
  1315  		// take the lock just before we output stuff, so at the last possible moment
  1316  		mu.Lock()
  1317  		defer mu.Unlock()
  1318  		_, err = io.Copy(w, in)
  1319  		if err != nil {
  1320  			err = fs.CountError(err)
  1321  			fs.Errorf(o, "Failed to send to output: %v", err)
  1322  		}
  1323  	})
  1324  }
  1325  
  1326  // Rcat reads data from the Reader until EOF and uploads it to a file on remote
  1327  func Rcat(ctx context.Context, fdst fs.Fs, dstFileName string, in io.ReadCloser, modTime time.Time) (dst fs.Object, err error) {
  1328  	tr := accounting.Stats(ctx).NewTransferRemoteSize(dstFileName, -1)
  1329  	defer func() {
  1330  		tr.Done(err)
  1331  	}()
  1332  	in = tr.Account(in).WithBuffer()
  1333  
  1334  	readCounter := readers.NewCountingReader(in)
  1335  	var trackingIn io.Reader
  1336  	var hasher *hash.MultiHasher
  1337  	var options []fs.OpenOption
  1338  	if !fs.Config.IgnoreChecksum {
  1339  		hashes := hash.NewHashSet(fdst.Hashes().GetOne()) // just pick one hash
  1340  		hashOption := &fs.HashesOption{Hashes: hashes}
  1341  		options = append(options, hashOption)
  1342  		hasher, err = hash.NewMultiHasherTypes(hashes)
  1343  		if err != nil {
  1344  			return nil, err
  1345  		}
  1346  		trackingIn = io.TeeReader(readCounter, hasher)
  1347  	} else {
  1348  		trackingIn = readCounter
  1349  	}
  1350  	for _, option := range fs.Config.UploadHeaders {
  1351  		options = append(options, option)
  1352  	}
  1353  
  1354  	compare := func(dst fs.Object) error {
  1355  		var sums map[hash.Type]string
  1356  		if hasher != nil {
  1357  			sums = hasher.Sums()
  1358  		}
  1359  		src := object.NewStaticObjectInfo(dstFileName, modTime, int64(readCounter.BytesRead()), false, sums, fdst)
  1360  		if !Equal(ctx, src, dst) {
  1361  			err = errors.Errorf("corrupted on transfer")
  1362  			err = fs.CountError(err)
  1363  			fs.Errorf(dst, "%v", err)
  1364  			return err
  1365  		}
  1366  		return nil
  1367  	}
  1368  
  1369  	// check if file small enough for direct upload
  1370  	buf := make([]byte, fs.Config.StreamingUploadCutoff)
  1371  	if n, err := io.ReadFull(trackingIn, buf); err == io.EOF || err == io.ErrUnexpectedEOF {
  1372  		fs.Debugf(fdst, "File to upload is small (%d bytes), uploading instead of streaming", n)
  1373  		src := object.NewMemoryObject(dstFileName, modTime, buf[:n])
  1374  		return Copy(ctx, fdst, nil, dstFileName, src)
  1375  	}
  1376  
  1377  	// Make a new ReadCloser with the bits we've already read
  1378  	in = &readCloser{
  1379  		Reader: io.MultiReader(bytes.NewReader(buf), trackingIn),
  1380  		Closer: in,
  1381  	}
  1382  
  1383  	fStreamTo := fdst
  1384  	canStream := fdst.Features().PutStream != nil
  1385  	if !canStream {
  1386  		fs.Debugf(fdst, "Target remote doesn't support streaming uploads, creating temporary local FS to spool file")
  1387  		tmpLocalFs, err := fs.TemporaryLocalFs()
  1388  		if err != nil {
  1389  			return nil, errors.Wrap(err, "Failed to create temporary local FS to spool file")
  1390  		}
  1391  		defer func() {
  1392  			err := Purge(ctx, tmpLocalFs, "")
  1393  			if err != nil {
  1394  				fs.Infof(tmpLocalFs, "Failed to cleanup temporary FS: %v", err)
  1395  			}
  1396  		}()
  1397  		fStreamTo = tmpLocalFs
  1398  	}
  1399  
  1400  	if fs.Config.DryRun {
  1401  		fs.Logf("stdin", "Not uploading as --dry-run")
  1402  		// prevents "broken pipe" errors
  1403  		_, err = io.Copy(ioutil.Discard, in)
  1404  		return nil, err
  1405  	}
  1406  
  1407  	objInfo := object.NewStaticObjectInfo(dstFileName, modTime, -1, false, nil, nil)
  1408  	if dst, err = fStreamTo.Features().PutStream(ctx, in, objInfo, options...); err != nil {
  1409  		return dst, err
  1410  	}
  1411  	if err = compare(dst); err != nil {
  1412  		return dst, err
  1413  	}
  1414  	if !canStream {
  1415  		// copy dst (which is the local object we have just streamed to) to the remote
  1416  		return Copy(ctx, fdst, nil, dstFileName, dst)
  1417  	}
  1418  	return dst, nil
  1419  }
  1420  
  1421  // PublicLink adds a "readable by anyone with link" permission on the given file or folder.
  1422  func PublicLink(ctx context.Context, f fs.Fs, remote string) (string, error) {
  1423  	doPublicLink := f.Features().PublicLink
  1424  	if doPublicLink == nil {
  1425  		return "", errors.Errorf("%v doesn't support public links", f)
  1426  	}
  1427  	return doPublicLink(ctx, remote)
  1428  }
  1429  
  1430  // Rmdirs removes any empty directories (or directories only
  1431  // containing empty directories) under f, including f.
  1432  func Rmdirs(ctx context.Context, f fs.Fs, dir string, leaveRoot bool) error {
  1433  	dirEmpty := make(map[string]bool)
  1434  	dirEmpty[dir] = !leaveRoot
  1435  	err := walk.Walk(ctx, f, dir, true, fs.Config.MaxDepth, func(dirPath string, entries fs.DirEntries, err error) error {
  1436  		if err != nil {
  1437  			err = fs.CountError(err)
  1438  			fs.Errorf(f, "Failed to list %q: %v", dirPath, err)
  1439  			return nil
  1440  		}
  1441  		for _, entry := range entries {
  1442  			switch x := entry.(type) {
  1443  			case fs.Directory:
  1444  				// add a new directory as empty
  1445  				dir := x.Remote()
  1446  				_, found := dirEmpty[dir]
  1447  				if !found {
  1448  					dirEmpty[dir] = true
  1449  				}
  1450  			case fs.Object:
  1451  				// mark the parents of the file as being non-empty
  1452  				dir := x.Remote()
  1453  				for dir != "" {
  1454  					dir = path.Dir(dir)
  1455  					if dir == "." || dir == "/" {
  1456  						dir = ""
  1457  					}
  1458  					empty, found := dirEmpty[dir]
  1459  					// End if we reach a directory which is non-empty
  1460  					if found && !empty {
  1461  						break
  1462  					}
  1463  					dirEmpty[dir] = false
  1464  				}
  1465  			}
  1466  		}
  1467  		return nil
  1468  	})
  1469  	if err != nil {
  1470  		return errors.Wrap(err, "failed to rmdirs")
  1471  	}
  1472  	// Now delete the empty directories, starting from the longest path
  1473  	var toDelete []string
  1474  	for dir, empty := range dirEmpty {
  1475  		if empty {
  1476  			toDelete = append(toDelete, dir)
  1477  		}
  1478  	}
  1479  	sort.Strings(toDelete)
  1480  	for i := len(toDelete) - 1; i >= 0; i-- {
  1481  		dir := toDelete[i]
  1482  		err := TryRmdir(ctx, f, dir)
  1483  		if err != nil {
  1484  			err = fs.CountError(err)
  1485  			fs.Errorf(dir, "Failed to rmdir: %v", err)
  1486  			return err
  1487  		}
  1488  	}
  1489  	return nil
  1490  }
  1491  
  1492  // GetCompareDest sets up --compare-dest
  1493  func GetCompareDest() (CompareDest fs.Fs, err error) {
  1494  	CompareDest, err = cache.Get(fs.Config.CompareDest)
  1495  	if err != nil {
  1496  		return nil, fserrors.FatalError(errors.Errorf("Failed to make fs for --compare-dest %q: %v", fs.Config.CompareDest, err))
  1497  	}
  1498  	return CompareDest, nil
  1499  }
  1500  
  1501  // compareDest checks --compare-dest to see if src needs to
  1502  // be copied
  1503  //
  1504  // Returns True if src is in --compare-dest
  1505  func compareDest(ctx context.Context, dst, src fs.Object, CompareDest fs.Fs) (NoNeedTransfer bool, err error) {
  1506  	var remote string
  1507  	if dst == nil {
  1508  		remote = src.Remote()
  1509  	} else {
  1510  		remote = dst.Remote()
  1511  	}
  1512  	CompareDestFile, err := CompareDest.NewObject(ctx, remote)
  1513  	switch err {
  1514  	case fs.ErrorObjectNotFound:
  1515  		return false, nil
  1516  	case nil:
  1517  		break
  1518  	default:
  1519  		return false, err
  1520  	}
  1521  	if Equal(ctx, src, CompareDestFile) {
  1522  		fs.Debugf(src, "Destination found in --compare-dest, skipping")
  1523  		return true, nil
  1524  	}
  1525  	return false, nil
  1526  }
  1527  
  1528  // GetCopyDest sets up --copy-dest
  1529  func GetCopyDest(fdst fs.Fs) (CopyDest fs.Fs, err error) {
  1530  	CopyDest, err = cache.Get(fs.Config.CopyDest)
  1531  	if err != nil {
  1532  		return nil, fserrors.FatalError(errors.Errorf("Failed to make fs for --copy-dest %q: %v", fs.Config.CopyDest, err))
  1533  	}
  1534  	if !SameConfig(fdst, CopyDest) {
  1535  		return nil, fserrors.FatalError(errors.New("parameter to --copy-dest has to be on the same remote as destination"))
  1536  	}
  1537  	if CopyDest.Features().Copy == nil {
  1538  		return nil, fserrors.FatalError(errors.New("can't use --copy-dest on a remote which doesn't support server side copy"))
  1539  	}
  1540  	return CopyDest, nil
  1541  }
  1542  
  1543  // copyDest checks --copy-dest to see if src needs to
  1544  // be copied
  1545  //
  1546  // Returns True if src was copied from --copy-dest
  1547  func copyDest(ctx context.Context, fdst fs.Fs, dst, src fs.Object, CopyDest, backupDir fs.Fs) (NoNeedTransfer bool, err error) {
  1548  	var remote string
  1549  	if dst == nil {
  1550  		remote = src.Remote()
  1551  	} else {
  1552  		remote = dst.Remote()
  1553  	}
  1554  	CopyDestFile, err := CopyDest.NewObject(ctx, remote)
  1555  	switch err {
  1556  	case fs.ErrorObjectNotFound:
  1557  		return false, nil
  1558  	case nil:
  1559  		break
  1560  	default:
  1561  		return false, err
  1562  	}
  1563  	opt := defaultEqualOpt()
  1564  	opt.updateModTime = false
  1565  	if equal(ctx, src, CopyDestFile, opt) {
  1566  		if dst == nil || !Equal(ctx, src, dst) {
  1567  			if dst != nil && backupDir != nil {
  1568  				err = MoveBackupDir(ctx, backupDir, dst)
  1569  				if err != nil {
  1570  					return false, errors.Wrap(err, "moving to --backup-dir failed")
  1571  				}
  1572  				// If successful zero out the dstObj as it is no longer there
  1573  				dst = nil
  1574  			}
  1575  			_, err := Copy(ctx, fdst, dst, remote, CopyDestFile)
  1576  			if err != nil {
  1577  				fs.Errorf(src, "Destination found in --copy-dest, error copying")
  1578  				return false, nil
  1579  			}
  1580  			fs.Debugf(src, "Destination found in --copy-dest, using server side copy")
  1581  			return true, nil
  1582  		}
  1583  		fs.Debugf(src, "Unchanged skipping")
  1584  		return true, nil
  1585  	}
  1586  	fs.Debugf(src, "Destination not found in --copy-dest")
  1587  	return false, nil
  1588  }
  1589  
  1590  // CompareOrCopyDest checks --compare-dest and --copy-dest to see if src
  1591  // does not need to be copied
  1592  //
  1593  // Returns True if src does not need to be copied
  1594  func CompareOrCopyDest(ctx context.Context, fdst fs.Fs, dst, src fs.Object, CompareOrCopyDest, backupDir fs.Fs) (NoNeedTransfer bool, err error) {
  1595  	if fs.Config.CompareDest != "" {
  1596  		return compareDest(ctx, dst, src, CompareOrCopyDest)
  1597  	} else if fs.Config.CopyDest != "" {
  1598  		return copyDest(ctx, fdst, dst, src, CompareOrCopyDest, backupDir)
  1599  	}
  1600  	return false, nil
  1601  }
  1602  
  1603  // NeedTransfer checks to see if src needs to be copied to dst using
  1604  // the current config.
  1605  //
  1606  // Returns a flag which indicates whether the file needs to be
  1607  // transferred or not.
  1608  func NeedTransfer(ctx context.Context, dst, src fs.Object) bool {
  1609  	if dst == nil {
  1610  		fs.Debugf(src, "Need to transfer - File not found at Destination")
  1611  		return true
  1612  	}
  1613  	// If we should ignore existing files, don't transfer
  1614  	if fs.Config.IgnoreExisting {
  1615  		fs.Debugf(src, "Destination exists, skipping")
  1616  		return false
  1617  	}
  1618  	// If we should upload unconditionally
  1619  	if fs.Config.IgnoreTimes {
  1620  		fs.Debugf(src, "Transferring unconditionally as --ignore-times is in use")
  1621  		return true
  1622  	}
  1623  	// If UpdateOlder is in effect, skip if dst is newer than src
  1624  	if fs.Config.UpdateOlder {
  1625  		srcModTime := src.ModTime(ctx)
  1626  		dstModTime := dst.ModTime(ctx)
  1627  		dt := dstModTime.Sub(srcModTime)
  1628  		// If have a mutually agreed precision then use that
  1629  		modifyWindow := fs.GetModifyWindow(dst.Fs(), src.Fs())
  1630  		if modifyWindow == fs.ModTimeNotSupported {
  1631  			// Otherwise use 1 second as a safe default as
  1632  			// the resolution of the time a file was
  1633  			// uploaded.
  1634  			modifyWindow = time.Second
  1635  		}
  1636  		switch {
  1637  		case dt >= modifyWindow:
  1638  			fs.Debugf(src, "Destination is newer than source, skipping")
  1639  			return false
  1640  		case dt <= -modifyWindow:
  1641  			// force --checksum on for the check and do update modtimes by default
  1642  			opt := defaultEqualOpt()
  1643  			opt.forceModTimeMatch = true
  1644  			if equal(ctx, src, dst, opt) {
  1645  				fs.Debugf(src, "Unchanged skipping")
  1646  				return false
  1647  			}
  1648  		default:
  1649  			// Do a size only compare unless --checksum is set
  1650  			opt := defaultEqualOpt()
  1651  			opt.sizeOnly = !fs.Config.CheckSum
  1652  			if equal(ctx, src, dst, opt) {
  1653  				fs.Debugf(src, "Destination mod time is within %v of source and files identical, skipping", modifyWindow)
  1654  				return false
  1655  			}
  1656  			fs.Debugf(src, "Destination mod time is within %v of source but files differ, transferring", modifyWindow)
  1657  		}
  1658  	} else {
  1659  		// Check to see if changed or not
  1660  		if Equal(ctx, src, dst) {
  1661  			fs.Debugf(src, "Unchanged skipping")
  1662  			return false
  1663  		}
  1664  	}
  1665  	return true
  1666  }
  1667  
  1668  // RcatSize reads data from the Reader until EOF and uploads it to a file on remote.
  1669  // Pass in size >=0 if known, <0 if not known
  1670  func RcatSize(ctx context.Context, fdst fs.Fs, dstFileName string, in io.ReadCloser, size int64, modTime time.Time) (dst fs.Object, err error) {
  1671  	var obj fs.Object
  1672  
  1673  	if size >= 0 {
  1674  		var err error
  1675  		// Size known use Put
  1676  		tr := accounting.Stats(ctx).NewTransferRemoteSize(dstFileName, size)
  1677  		defer func() {
  1678  			tr.Done(err)
  1679  		}()
  1680  		body := ioutil.NopCloser(in) // we let the server close the body
  1681  		in := tr.Account(body)       // account the transfer (no buffering)
  1682  
  1683  		if fs.Config.DryRun {
  1684  			fs.Logf("stdin", "Not uploading as --dry-run")
  1685  			// prevents "broken pipe" errors
  1686  			_, err = io.Copy(ioutil.Discard, in)
  1687  			return nil, err
  1688  		}
  1689  
  1690  		info := object.NewStaticObjectInfo(dstFileName, modTime, size, true, nil, fdst)
  1691  		obj, err = fdst.Put(ctx, in, info)
  1692  		if err != nil {
  1693  			fs.Errorf(dstFileName, "Post request put error: %v", err)
  1694  
  1695  			return nil, err
  1696  		}
  1697  	} else {
  1698  		// Size unknown use Rcat
  1699  		obj, err = Rcat(ctx, fdst, dstFileName, in, modTime)
  1700  		if err != nil {
  1701  			fs.Errorf(dstFileName, "Post request rcat error: %v", err)
  1702  
  1703  			return nil, err
  1704  		}
  1705  	}
  1706  
  1707  	return obj, nil
  1708  }
  1709  
  1710  // copyURLFunc is called from CopyURLFn
  1711  type copyURLFunc func(ctx context.Context, dstFileName string, in io.ReadCloser, size int64, modTime time.Time) (err error)
  1712  
  1713  // copyURLFn copies the data from the url to the function supplied
  1714  func copyURLFn(ctx context.Context, dstFileName string, url string, dstFileNameFromURL bool, fn copyURLFunc) (err error) {
  1715  	client := fshttp.NewClient(fs.Config)
  1716  	resp, err := client.Get(url)
  1717  	if err != nil {
  1718  		return err
  1719  	}
  1720  	defer fs.CheckClose(resp.Body, &err)
  1721  	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
  1722  		return errors.Errorf("CopyURL failed: %s", resp.Status)
  1723  	}
  1724  	modTime, err := http.ParseTime(resp.Header.Get("Last-Modified"))
  1725  	if err != nil {
  1726  		modTime = time.Now()
  1727  	}
  1728  	if dstFileNameFromURL {
  1729  		dstFileName = path.Base(resp.Request.URL.Path)
  1730  		if dstFileName == "." || dstFileName == "/" {
  1731  			return errors.Errorf("CopyURL failed: file name wasn't found in url")
  1732  		}
  1733  	}
  1734  	return fn(ctx, dstFileName, resp.Body, resp.ContentLength, modTime)
  1735  }
  1736  
  1737  // CopyURL copies the data from the url to (fdst, dstFileName)
  1738  func CopyURL(ctx context.Context, fdst fs.Fs, dstFileName string, url string, dstFileNameFromURL bool, noClobber bool) (dst fs.Object, err error) {
  1739  
  1740  	err = copyURLFn(ctx, dstFileName, url, dstFileNameFromURL, func(ctx context.Context, dstFileName string, in io.ReadCloser, size int64, modTime time.Time) (err error) {
  1741  		if noClobber {
  1742  			_, err = fdst.NewObject(ctx, dstFileName)
  1743  			if err == nil {
  1744  				return errors.New("CopyURL failed: file already exist")
  1745  			}
  1746  		}
  1747  		dst, err = RcatSize(ctx, fdst, dstFileName, in, size, modTime)
  1748  		return err
  1749  	})
  1750  	return dst, err
  1751  }
  1752  
  1753  // CopyURLToWriter copies the data from the url to the io.Writer supplied
  1754  func CopyURLToWriter(ctx context.Context, url string, out io.Writer) (err error) {
  1755  	return copyURLFn(ctx, "", url, false, func(ctx context.Context, dstFileName string, in io.ReadCloser, size int64, modTime time.Time) (err error) {
  1756  		_, err = io.Copy(out, in)
  1757  		return err
  1758  	})
  1759  }
  1760  
  1761  // BackupDir returns the correctly configured --backup-dir
  1762  func BackupDir(fdst fs.Fs, fsrc fs.Fs, srcFileName string) (backupDir fs.Fs, err error) {
  1763  	if fs.Config.BackupDir != "" {
  1764  		backupDir, err = cache.Get(fs.Config.BackupDir)
  1765  		if err != nil {
  1766  			return nil, fserrors.FatalError(errors.Errorf("Failed to make fs for --backup-dir %q: %v", fs.Config.BackupDir, err))
  1767  		}
  1768  		if !SameConfig(fdst, backupDir) {
  1769  			return nil, fserrors.FatalError(errors.New("parameter to --backup-dir has to be on the same remote as destination"))
  1770  		}
  1771  		if srcFileName == "" {
  1772  			if Overlapping(fdst, backupDir) {
  1773  				return nil, fserrors.FatalError(errors.New("destination and parameter to --backup-dir mustn't overlap"))
  1774  			}
  1775  			if Overlapping(fsrc, backupDir) {
  1776  				return nil, fserrors.FatalError(errors.New("source and parameter to --backup-dir mustn't overlap"))
  1777  			}
  1778  		} else {
  1779  			if fs.Config.Suffix == "" {
  1780  				if SameDir(fdst, backupDir) {
  1781  					return nil, fserrors.FatalError(errors.New("destination and parameter to --backup-dir mustn't be the same"))
  1782  				}
  1783  				if SameDir(fsrc, backupDir) {
  1784  					return nil, fserrors.FatalError(errors.New("source and parameter to --backup-dir mustn't be the same"))
  1785  				}
  1786  			}
  1787  		}
  1788  	} else {
  1789  		if srcFileName == "" {
  1790  			return nil, fserrors.FatalError(errors.New("--suffix must be used with a file or with --backup-dir"))
  1791  		}
  1792  		// --backup-dir is not set but --suffix is - use the destination as the backupDir
  1793  		backupDir = fdst
  1794  	}
  1795  	if !CanServerSideMove(backupDir) {
  1796  		return nil, fserrors.FatalError(errors.New("can't use --backup-dir on a remote which doesn't support server side move or copy"))
  1797  	}
  1798  	return backupDir, nil
  1799  }
  1800  
  1801  // MoveBackupDir moves a file to the backup dir
  1802  func MoveBackupDir(ctx context.Context, backupDir fs.Fs, dst fs.Object) (err error) {
  1803  	remoteWithSuffix := SuffixName(dst.Remote())
  1804  	overwritten, _ := backupDir.NewObject(ctx, remoteWithSuffix)
  1805  	_, err = Move(ctx, backupDir, overwritten, remoteWithSuffix, dst)
  1806  	return err
  1807  }
  1808  
  1809  // moveOrCopyFile moves or copies a single file possibly to a new name
  1810  func moveOrCopyFile(ctx context.Context, fdst fs.Fs, fsrc fs.Fs, dstFileName string, srcFileName string, cp bool) (err error) {
  1811  	dstFilePath := path.Join(fdst.Root(), dstFileName)
  1812  	srcFilePath := path.Join(fsrc.Root(), srcFileName)
  1813  	if fdst.Name() == fsrc.Name() && dstFilePath == srcFilePath {
  1814  		fs.Debugf(fdst, "don't need to copy/move %s, it is already at target location", dstFileName)
  1815  		return nil
  1816  	}
  1817  
  1818  	// Choose operations
  1819  	Op := Move
  1820  	if cp {
  1821  		Op = Copy
  1822  	}
  1823  
  1824  	// Find src object
  1825  	srcObj, err := fsrc.NewObject(ctx, srcFileName)
  1826  	if err != nil {
  1827  		return err
  1828  	}
  1829  
  1830  	// Find dst object if it exists
  1831  	var dstObj fs.Object
  1832  	if !fs.Config.NoCheckDest {
  1833  		dstObj, err = fdst.NewObject(ctx, dstFileName)
  1834  		if err == fs.ErrorObjectNotFound {
  1835  			dstObj = nil
  1836  		} else if err != nil {
  1837  			return err
  1838  		}
  1839  	}
  1840  
  1841  	// Special case for changing case of a file on a case insensitive remote
  1842  	// This will move the file to a temporary name then
  1843  	// move it back to the intended destination. This is required
  1844  	// to avoid issues with certain remotes and avoid file deletion.
  1845  	if !cp && fdst.Name() == fsrc.Name() && fdst.Features().CaseInsensitive && dstFileName != srcFileName && strings.ToLower(dstFilePath) == strings.ToLower(srcFilePath) {
  1846  		// Create random name to temporarily move file to
  1847  		tmpObjName := dstFileName + "-rclone-move-" + random.String(8)
  1848  		_, err := fdst.NewObject(ctx, tmpObjName)
  1849  		if err != fs.ErrorObjectNotFound {
  1850  			if err == nil {
  1851  				return errors.New("found an already existing file with a randomly generated name. Try the operation again")
  1852  			}
  1853  			return errors.Wrap(err, "error while attempting to move file to a temporary location")
  1854  		}
  1855  		tr := accounting.Stats(ctx).NewTransfer(srcObj)
  1856  		defer func() {
  1857  			tr.Done(err)
  1858  		}()
  1859  		tmpObj, err := Op(ctx, fdst, nil, tmpObjName, srcObj)
  1860  		if err != nil {
  1861  			return errors.Wrap(err, "error while moving file to temporary location")
  1862  		}
  1863  		_, err = Op(ctx, fdst, nil, dstFileName, tmpObj)
  1864  		return err
  1865  	}
  1866  
  1867  	var backupDir, copyDestDir fs.Fs
  1868  	if fs.Config.BackupDir != "" || fs.Config.Suffix != "" {
  1869  		backupDir, err = BackupDir(fdst, fsrc, srcFileName)
  1870  		if err != nil {
  1871  			return errors.Wrap(err, "creating Fs for --backup-dir failed")
  1872  		}
  1873  	}
  1874  	if fs.Config.CompareDest != "" {
  1875  		copyDestDir, err = GetCompareDest()
  1876  		if err != nil {
  1877  			return err
  1878  		}
  1879  	} else if fs.Config.CopyDest != "" {
  1880  		copyDestDir, err = GetCopyDest(fdst)
  1881  		if err != nil {
  1882  			return err
  1883  		}
  1884  	}
  1885  	NoNeedTransfer, err := CompareOrCopyDest(ctx, fdst, dstObj, srcObj, copyDestDir, backupDir)
  1886  	if err != nil {
  1887  		return err
  1888  	}
  1889  	if !NoNeedTransfer && NeedTransfer(ctx, dstObj, srcObj) {
  1890  		// If destination already exists, then we must move it into --backup-dir if required
  1891  		if dstObj != nil && backupDir != nil {
  1892  			err = MoveBackupDir(ctx, backupDir, dstObj)
  1893  			if err != nil {
  1894  				return errors.Wrap(err, "moving to --backup-dir failed")
  1895  			}
  1896  			// If successful zero out the dstObj as it is no longer there
  1897  			dstObj = nil
  1898  		}
  1899  
  1900  		_, err = Op(ctx, fdst, dstObj, dstFileName, srcObj)
  1901  	} else {
  1902  		tr := accounting.Stats(ctx).NewCheckingTransfer(srcObj)
  1903  		if !cp {
  1904  			err = DeleteFile(ctx, srcObj)
  1905  		}
  1906  		tr.Done(err)
  1907  	}
  1908  	return err
  1909  }
  1910  
  1911  // MoveFile moves a single file possibly to a new name
  1912  func MoveFile(ctx context.Context, fdst fs.Fs, fsrc fs.Fs, dstFileName string, srcFileName string) (err error) {
  1913  	return moveOrCopyFile(ctx, fdst, fsrc, dstFileName, srcFileName, false)
  1914  }
  1915  
  1916  // CopyFile moves a single file possibly to a new name
  1917  func CopyFile(ctx context.Context, fdst fs.Fs, fsrc fs.Fs, dstFileName string, srcFileName string) (err error) {
  1918  	return moveOrCopyFile(ctx, fdst, fsrc, dstFileName, srcFileName, true)
  1919  }
  1920  
  1921  // SetTier changes tier of object in remote
  1922  func SetTier(ctx context.Context, fsrc fs.Fs, tier string) error {
  1923  	return ListFn(ctx, fsrc, func(o fs.Object) {
  1924  		objImpl, ok := o.(fs.SetTierer)
  1925  		if !ok {
  1926  			fs.Errorf(fsrc, "Remote object does not implement SetTier")
  1927  			return
  1928  		}
  1929  		err := objImpl.SetTier(tier)
  1930  		if err != nil {
  1931  			fs.Errorf(fsrc, "Failed to do SetTier, %v", err)
  1932  		}
  1933  	})
  1934  }
  1935  
  1936  // ListFormat defines files information print format
  1937  type ListFormat struct {
  1938  	separator string
  1939  	dirSlash  bool
  1940  	absolute  bool
  1941  	output    []func(entry *ListJSONItem) string
  1942  	csv       *csv.Writer
  1943  	buf       bytes.Buffer
  1944  }
  1945  
  1946  // SetSeparator changes separator in struct
  1947  func (l *ListFormat) SetSeparator(separator string) {
  1948  	l.separator = separator
  1949  }
  1950  
  1951  // SetDirSlash defines if slash should be printed
  1952  func (l *ListFormat) SetDirSlash(dirSlash bool) {
  1953  	l.dirSlash = dirSlash
  1954  }
  1955  
  1956  // SetAbsolute prints a leading slash in front of path names
  1957  func (l *ListFormat) SetAbsolute(absolute bool) {
  1958  	l.absolute = absolute
  1959  }
  1960  
  1961  // SetCSV defines if the output should be csv
  1962  //
  1963  // Note that you should call SetSeparator before this if you want a
  1964  // custom separator
  1965  func (l *ListFormat) SetCSV(useCSV bool) {
  1966  	if useCSV {
  1967  		l.csv = csv.NewWriter(&l.buf)
  1968  		if l.separator != "" {
  1969  			l.csv.Comma = []rune(l.separator)[0]
  1970  		}
  1971  	} else {
  1972  		l.csv = nil
  1973  	}
  1974  }
  1975  
  1976  // SetOutput sets functions used to create files information
  1977  func (l *ListFormat) SetOutput(output []func(entry *ListJSONItem) string) {
  1978  	l.output = output
  1979  }
  1980  
  1981  // AddModTime adds file's Mod Time to output
  1982  func (l *ListFormat) AddModTime() {
  1983  	l.AppendOutput(func(entry *ListJSONItem) string {
  1984  		return entry.ModTime.When.Local().Format("2006-01-02 15:04:05")
  1985  	})
  1986  }
  1987  
  1988  // AddSize adds file's size to output
  1989  func (l *ListFormat) AddSize() {
  1990  	l.AppendOutput(func(entry *ListJSONItem) string {
  1991  		return strconv.FormatInt(entry.Size, 10)
  1992  	})
  1993  }
  1994  
  1995  // normalisePath makes sure the path has the correct slashes for the current mode
  1996  func (l *ListFormat) normalisePath(entry *ListJSONItem, remote string) string {
  1997  	if l.absolute && !strings.HasPrefix(remote, "/") {
  1998  		remote = "/" + remote
  1999  	}
  2000  	if entry.IsDir && l.dirSlash {
  2001  		remote += "/"
  2002  	}
  2003  	return remote
  2004  }
  2005  
  2006  // AddPath adds path to file to output
  2007  func (l *ListFormat) AddPath() {
  2008  	l.AppendOutput(func(entry *ListJSONItem) string {
  2009  		return l.normalisePath(entry, entry.Path)
  2010  	})
  2011  }
  2012  
  2013  // AddEncrypted adds the encrypted path to file to output
  2014  func (l *ListFormat) AddEncrypted() {
  2015  	l.AppendOutput(func(entry *ListJSONItem) string {
  2016  		return l.normalisePath(entry, entry.Encrypted)
  2017  	})
  2018  }
  2019  
  2020  // AddHash adds the hash of the type given to the output
  2021  func (l *ListFormat) AddHash(ht hash.Type) {
  2022  	hashName := ht.String()
  2023  	l.AppendOutput(func(entry *ListJSONItem) string {
  2024  		if entry.IsDir {
  2025  			return ""
  2026  		}
  2027  		return entry.Hashes[hashName]
  2028  	})
  2029  }
  2030  
  2031  // AddID adds file's ID to the output if known
  2032  func (l *ListFormat) AddID() {
  2033  	l.AppendOutput(func(entry *ListJSONItem) string {
  2034  		return entry.ID
  2035  	})
  2036  }
  2037  
  2038  // AddOrigID adds file's Original ID to the output if known
  2039  func (l *ListFormat) AddOrigID() {
  2040  	l.AppendOutput(func(entry *ListJSONItem) string {
  2041  		return entry.OrigID
  2042  	})
  2043  }
  2044  
  2045  // AddTier adds file's Tier to the output if known
  2046  func (l *ListFormat) AddTier() {
  2047  	l.AppendOutput(func(entry *ListJSONItem) string {
  2048  		return entry.Tier
  2049  	})
  2050  }
  2051  
  2052  // AddMimeType adds file's MimeType to the output if known
  2053  func (l *ListFormat) AddMimeType() {
  2054  	l.AppendOutput(func(entry *ListJSONItem) string {
  2055  		return entry.MimeType
  2056  	})
  2057  }
  2058  
  2059  // AppendOutput adds string generated by specific function to printed output
  2060  func (l *ListFormat) AppendOutput(functionToAppend func(item *ListJSONItem) string) {
  2061  	l.output = append(l.output, functionToAppend)
  2062  }
  2063  
  2064  // Format prints information about the DirEntry in the format defined
  2065  func (l *ListFormat) Format(entry *ListJSONItem) (result string) {
  2066  	var out []string
  2067  	for _, fun := range l.output {
  2068  		out = append(out, fun(entry))
  2069  	}
  2070  	if l.csv != nil {
  2071  		l.buf.Reset()
  2072  		_ = l.csv.Write(out) // can't fail writing to bytes.Buffer
  2073  		l.csv.Flush()
  2074  		result = strings.TrimRight(l.buf.String(), "\n")
  2075  	} else {
  2076  		result = strings.Join(out, l.separator)
  2077  	}
  2078  	return result
  2079  }
  2080  
  2081  // DirMove renames srcRemote to dstRemote
  2082  //
  2083  // It does this by loading the directory tree into memory (using ListR
  2084  // if available) and doing renames in parallel.
  2085  func DirMove(ctx context.Context, f fs.Fs, srcRemote, dstRemote string) (err error) {
  2086  	// Use DirMove if possible
  2087  	if doDirMove := f.Features().DirMove; doDirMove != nil {
  2088  		err = doDirMove(ctx, f, srcRemote, dstRemote)
  2089  		if err == nil {
  2090  			accounting.Stats(ctx).Renames(1)
  2091  		}
  2092  		return err
  2093  	}
  2094  
  2095  	// Load the directory tree into memory
  2096  	tree, err := walk.NewDirTree(ctx, f, srcRemote, true, -1)
  2097  	if err != nil {
  2098  		return errors.Wrap(err, "RenameDir tree walk")
  2099  	}
  2100  
  2101  	// Get the directories in sorted order
  2102  	dirs := tree.Dirs()
  2103  
  2104  	// Make the destination directories - must be done in order not in parallel
  2105  	for _, dir := range dirs {
  2106  		dstPath := dstRemote + dir[len(srcRemote):]
  2107  		err := f.Mkdir(ctx, dstPath)
  2108  		if err != nil {
  2109  			return errors.Wrap(err, "RenameDir mkdir")
  2110  		}
  2111  	}
  2112  
  2113  	// Rename the files in parallel
  2114  	type rename struct {
  2115  		o       fs.Object
  2116  		newPath string
  2117  	}
  2118  	renames := make(chan rename, fs.Config.Transfers)
  2119  	g, gCtx := errgroup.WithContext(context.Background())
  2120  	for i := 0; i < fs.Config.Transfers; i++ {
  2121  		g.Go(func() error {
  2122  			for job := range renames {
  2123  				dstOverwritten, _ := f.NewObject(gCtx, job.newPath)
  2124  				_, err := Move(gCtx, f, dstOverwritten, job.newPath, job.o)
  2125  				if err != nil {
  2126  					return err
  2127  				}
  2128  				select {
  2129  				case <-gCtx.Done():
  2130  					return gCtx.Err()
  2131  				default:
  2132  				}
  2133  
  2134  			}
  2135  			return nil
  2136  		})
  2137  	}
  2138  	for dir, entries := range tree {
  2139  		dstPath := dstRemote + dir[len(srcRemote):]
  2140  		for _, entry := range entries {
  2141  			if o, ok := entry.(fs.Object); ok {
  2142  				renames <- rename{o, path.Join(dstPath, path.Base(o.Remote()))}
  2143  			}
  2144  		}
  2145  	}
  2146  	close(renames)
  2147  	err = g.Wait()
  2148  	if err != nil {
  2149  		return errors.Wrap(err, "RenameDir renames")
  2150  	}
  2151  
  2152  	// Remove the source directories in reverse order
  2153  	for i := len(dirs) - 1; i >= 0; i-- {
  2154  		err := f.Rmdir(ctx, dirs[i])
  2155  		if err != nil {
  2156  			return errors.Wrap(err, "RenameDir rmdir")
  2157  		}
  2158  	}
  2159  
  2160  	return nil
  2161  }
  2162  
  2163  // FsInfo provides information about a remote
  2164  type FsInfo struct {
  2165  	// Name of the remote (as passed into NewFs)
  2166  	Name string
  2167  
  2168  	// Root of the remote (as passed into NewFs)
  2169  	Root string
  2170  
  2171  	// String returns a description of the FS
  2172  	String string
  2173  
  2174  	// Precision of the ModTimes in this Fs in Nanoseconds
  2175  	Precision time.Duration
  2176  
  2177  	// Returns the supported hash types of the filesystem
  2178  	Hashes []string
  2179  
  2180  	// Features returns the optional features of this Fs
  2181  	Features map[string]bool
  2182  }
  2183  
  2184  // GetFsInfo gets the information (FsInfo) about a given Fs
  2185  func GetFsInfo(f fs.Fs) *FsInfo {
  2186  	info := &FsInfo{
  2187  		Name:      f.Name(),
  2188  		Root:      f.Root(),
  2189  		String:    f.String(),
  2190  		Precision: f.Precision(),
  2191  		Hashes:    make([]string, 0, 4),
  2192  		Features:  f.Features().Enabled(),
  2193  	}
  2194  	for _, hashType := range f.Hashes().Array() {
  2195  		info.Hashes = append(info.Hashes, hashType.String())
  2196  	}
  2197  	return info
  2198  }