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