github.com/ncw/rclone@v1.48.1-0.20190724201158-a35aa1360e3e/fs/fs.go (about)

     1  // Package fs is a generic file system interface for rclone object storage systems
     2  package fs
     3  
     4  import (
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"log"
    11  	"math"
    12  	"os"
    13  	"path/filepath"
    14  	"reflect"
    15  	"sort"
    16  	"strings"
    17  	"time"
    18  
    19  	"github.com/ncw/rclone/fs/config/configmap"
    20  	"github.com/ncw/rclone/fs/config/configstruct"
    21  	"github.com/ncw/rclone/fs/fserrors"
    22  	"github.com/ncw/rclone/fs/fspath"
    23  	"github.com/ncw/rclone/fs/hash"
    24  	"github.com/ncw/rclone/lib/pacer"
    25  	"github.com/pkg/errors"
    26  )
    27  
    28  // EntryType can be associated with remote paths to identify their type
    29  type EntryType int
    30  
    31  // Constants
    32  const (
    33  	// ModTimeNotSupported is a very large precision value to show
    34  	// mod time isn't supported on this Fs
    35  	ModTimeNotSupported = 100 * 365 * 24 * time.Hour
    36  	// MaxLevel is a sentinel representing an infinite depth for listings
    37  	MaxLevel = math.MaxInt32
    38  	// EntryDirectory should be used to classify remote paths in directories
    39  	EntryDirectory EntryType = iota // 0
    40  	// EntryObject should be used to classify remote paths in objects
    41  	EntryObject // 1
    42  )
    43  
    44  // Globals
    45  var (
    46  	// Filesystem registry
    47  	Registry []*RegInfo
    48  	// ErrorNotFoundInConfigFile is returned by NewFs if not found in config file
    49  	ErrorNotFoundInConfigFile        = errors.New("didn't find section in config file")
    50  	ErrorCantPurge                   = errors.New("can't purge directory")
    51  	ErrorCantCopy                    = errors.New("can't copy object - incompatible remotes")
    52  	ErrorCantMove                    = errors.New("can't move object - incompatible remotes")
    53  	ErrorCantDirMove                 = errors.New("can't move directory - incompatible remotes")
    54  	ErrorCantUploadEmptyFiles        = errors.New("can't upload empty files to this remote")
    55  	ErrorDirExists                   = errors.New("can't copy directory - destination already exists")
    56  	ErrorCantSetModTime              = errors.New("can't set modified time")
    57  	ErrorCantSetModTimeWithoutDelete = errors.New("can't set modified time without deleting existing object")
    58  	ErrorDirNotFound                 = errors.New("directory not found")
    59  	ErrorObjectNotFound              = errors.New("object not found")
    60  	ErrorLevelNotSupported           = errors.New("level value not supported")
    61  	ErrorListAborted                 = errors.New("list aborted")
    62  	ErrorListBucketRequired          = errors.New("bucket or container name is needed in remote")
    63  	ErrorIsFile                      = errors.New("is a file not a directory")
    64  	ErrorNotAFile                    = errors.New("is a not a regular file")
    65  	ErrorNotDeleting                 = errors.New("not deleting files as there were IO errors")
    66  	ErrorNotDeletingDirs             = errors.New("not deleting directories as there were IO errors")
    67  	ErrorOverlapping                 = errors.New("can't sync or move files on overlapping remotes")
    68  	ErrorDirectoryNotEmpty           = errors.New("directory not empty")
    69  	ErrorImmutableModified           = errors.New("immutable file modified")
    70  	ErrorPermissionDenied            = errors.New("permission denied")
    71  	ErrorCantShareDirectories        = errors.New("this backend can't share directories with link")
    72  )
    73  
    74  // RegInfo provides information about a filesystem
    75  type RegInfo struct {
    76  	// Name of this fs
    77  	Name string
    78  	// Description of this fs - defaults to Name
    79  	Description string
    80  	// Prefix for command line flags for this fs - defaults to Name if not set
    81  	Prefix string
    82  	// Create a new file system.  If root refers to an existing
    83  	// object, then it should return a Fs which which points to
    84  	// the parent of that object and ErrorIsFile.
    85  	NewFs func(name string, root string, config configmap.Mapper) (Fs, error) `json:"-"`
    86  	// Function to call to help with config
    87  	Config func(name string, config configmap.Mapper) `json:"-"`
    88  	// Options for the Fs configuration
    89  	Options Options
    90  }
    91  
    92  // FileName returns the on disk file name for this backend
    93  func (ri *RegInfo) FileName() string {
    94  	return strings.Replace(ri.Name, " ", "", -1)
    95  }
    96  
    97  // Options is a slice of configuration Option for a backend
    98  type Options []Option
    99  
   100  // Set the default values for the options
   101  func (os Options) setValues() {
   102  	for i := range os {
   103  		o := &os[i]
   104  		if o.Default == nil {
   105  			o.Default = ""
   106  		}
   107  	}
   108  }
   109  
   110  // OptionVisibility controls whether the options are visible in the
   111  // configurator or the command line.
   112  type OptionVisibility byte
   113  
   114  // Constants Option.Hide
   115  const (
   116  	OptionHideCommandLine OptionVisibility = 1 << iota
   117  	OptionHideConfigurator
   118  	OptionHideBoth = OptionHideCommandLine | OptionHideConfigurator
   119  )
   120  
   121  // Option is describes an option for the config wizard
   122  //
   123  // This also describes command line options and environment variables
   124  type Option struct {
   125  	Name       string           // name of the option in snake_case
   126  	Help       string           // Help, the first line only is used for the command line help
   127  	Provider   string           // Set to filter on provider
   128  	Default    interface{}      // default value, nil => ""
   129  	Value      interface{}      // value to be set by flags
   130  	Examples   OptionExamples   `json:",omitempty"` // config examples
   131  	ShortOpt   string           // the short option for this if required
   132  	Hide       OptionVisibility // set this to hide the config from the configurator or the command line
   133  	Required   bool             // this option is required
   134  	IsPassword bool             // set if the option is a password
   135  	NoPrefix   bool             // set if the option for this should not use the backend prefix
   136  	Advanced   bool             // set if this is an advanced config option
   137  }
   138  
   139  // BaseOption is an alias for Option used internally
   140  type BaseOption Option
   141  
   142  // MarshalJSON turns an Option into JSON
   143  //
   144  // It adds some generated fields for ease of use
   145  // - DefaultStr - a string rendering of Default
   146  // - ValueStr - a string rendering of Value
   147  // - Type - the type of the option
   148  func (o *Option) MarshalJSON() ([]byte, error) {
   149  	return json.Marshal(struct {
   150  		BaseOption
   151  		DefaultStr string
   152  		ValueStr   string
   153  		Type       string
   154  	}{
   155  		BaseOption: BaseOption(*o),
   156  		DefaultStr: fmt.Sprint(o.Default),
   157  		ValueStr:   o.String(),
   158  		Type:       o.Type(),
   159  	})
   160  }
   161  
   162  // GetValue gets the current current value which is the default if not set
   163  func (o *Option) GetValue() interface{} {
   164  	val := o.Value
   165  	if val == nil {
   166  		val = o.Default
   167  	}
   168  	return val
   169  }
   170  
   171  // String turns Option into a string
   172  func (o *Option) String() string {
   173  	return fmt.Sprint(o.GetValue())
   174  }
   175  
   176  // Set a Option from a string
   177  func (o *Option) Set(s string) (err error) {
   178  	newValue, err := configstruct.StringToInterface(o.GetValue(), s)
   179  	if err != nil {
   180  		return err
   181  	}
   182  	o.Value = newValue
   183  	return nil
   184  }
   185  
   186  // Type of the value
   187  func (o *Option) Type() string {
   188  	return reflect.TypeOf(o.GetValue()).Name()
   189  }
   190  
   191  // FlagName for the option
   192  func (o *Option) FlagName(prefix string) string {
   193  	name := strings.Replace(o.Name, "_", "-", -1) // convert snake_case to kebab-case
   194  	if !o.NoPrefix {
   195  		name = prefix + "-" + name
   196  	}
   197  	return name
   198  }
   199  
   200  // EnvVarName for the option
   201  func (o *Option) EnvVarName(prefix string) string {
   202  	return OptionToEnv(prefix + "-" + o.Name)
   203  }
   204  
   205  // OptionExamples is a slice of examples
   206  type OptionExamples []OptionExample
   207  
   208  // Len is part of sort.Interface.
   209  func (os OptionExamples) Len() int { return len(os) }
   210  
   211  // Swap is part of sort.Interface.
   212  func (os OptionExamples) Swap(i, j int) { os[i], os[j] = os[j], os[i] }
   213  
   214  // Less is part of sort.Interface.
   215  func (os OptionExamples) Less(i, j int) bool { return os[i].Help < os[j].Help }
   216  
   217  // Sort sorts an OptionExamples
   218  func (os OptionExamples) Sort() { sort.Sort(os) }
   219  
   220  // OptionExample describes an example for an Option
   221  type OptionExample struct {
   222  	Value    string
   223  	Help     string
   224  	Provider string
   225  }
   226  
   227  // Register a filesystem
   228  //
   229  // Fs modules  should use this in an init() function
   230  func Register(info *RegInfo) {
   231  	info.Options.setValues()
   232  	if info.Prefix == "" {
   233  		info.Prefix = info.Name
   234  	}
   235  	Registry = append(Registry, info)
   236  }
   237  
   238  // Fs is the interface a cloud storage system must provide
   239  type Fs interface {
   240  	Info
   241  
   242  	// List the objects and directories in dir into entries.  The
   243  	// entries can be returned in any order but should be for a
   244  	// complete directory.
   245  	//
   246  	// dir should be "" to list the root, and should not have
   247  	// trailing slashes.
   248  	//
   249  	// This should return ErrDirNotFound if the directory isn't
   250  	// found.
   251  	List(ctx context.Context, dir string) (entries DirEntries, err error)
   252  
   253  	// NewObject finds the Object at remote.  If it can't be found
   254  	// it returns the error ErrorObjectNotFound.
   255  	NewObject(ctx context.Context, remote string) (Object, error)
   256  
   257  	// Put in to the remote path with the modTime given of the given size
   258  	//
   259  	// When called from outside a Fs by rclone, src.Size() will always be >= 0.
   260  	// But for unknown-sized objects (indicated by src.Size() == -1), Put should either
   261  	// return an error or upload it properly (rather than e.g. calling panic).
   262  	//
   263  	// May create the object even if it returns an error - if so
   264  	// will return the object and the error, otherwise will return
   265  	// nil and the error
   266  	Put(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
   267  
   268  	// Mkdir makes the directory (container, bucket)
   269  	//
   270  	// Shouldn't return an error if it already exists
   271  	Mkdir(ctx context.Context, dir string) error
   272  
   273  	// Rmdir removes the directory (container, bucket) if empty
   274  	//
   275  	// Return an error if it doesn't exist or isn't empty
   276  	Rmdir(ctx context.Context, dir string) error
   277  }
   278  
   279  // Info provides a read only interface to information about a filesystem.
   280  type Info interface {
   281  	// Name of the remote (as passed into NewFs)
   282  	Name() string
   283  
   284  	// Root of the remote (as passed into NewFs)
   285  	Root() string
   286  
   287  	// String returns a description of the FS
   288  	String() string
   289  
   290  	// Precision of the ModTimes in this Fs
   291  	Precision() time.Duration
   292  
   293  	// Returns the supported hash types of the filesystem
   294  	Hashes() hash.Set
   295  
   296  	// Features returns the optional features of this Fs
   297  	Features() *Features
   298  }
   299  
   300  // Object is a filesystem like object provided by an Fs
   301  type Object interface {
   302  	ObjectInfo
   303  
   304  	// SetModTime sets the metadata on the object to set the modification date
   305  	SetModTime(ctx context.Context, t time.Time) error
   306  
   307  	// Open opens the file for read.  Call Close() on the returned io.ReadCloser
   308  	Open(ctx context.Context, options ...OpenOption) (io.ReadCloser, error)
   309  
   310  	// Update in to the object with the modTime given of the given size
   311  	//
   312  	// When called from outside a Fs by rclone, src.Size() will always be >= 0.
   313  	// But for unknown-sized objects (indicated by src.Size() == -1), Upload should either
   314  	// return an error or update the object properly (rather than e.g. calling panic).
   315  	Update(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) error
   316  
   317  	// Removes this object
   318  	Remove(ctx context.Context) error
   319  }
   320  
   321  // ObjectInfo provides read only information about an object.
   322  type ObjectInfo interface {
   323  	DirEntry
   324  
   325  	// Fs returns read only access to the Fs that this object is part of
   326  	Fs() Info
   327  
   328  	// Hash returns the selected checksum of the file
   329  	// If no checksum is available it returns ""
   330  	Hash(ctx context.Context, ty hash.Type) (string, error)
   331  
   332  	// Storable says whether this object can be stored
   333  	Storable() bool
   334  }
   335  
   336  // DirEntry provides read only information about the common subset of
   337  // a Dir or Object.  These are returned from directory listings - type
   338  // assert them into the correct type.
   339  type DirEntry interface {
   340  	// String returns a description of the Object
   341  	String() string
   342  
   343  	// Remote returns the remote path
   344  	Remote() string
   345  
   346  	// ModTime returns the modification date of the file
   347  	// It should return a best guess if one isn't available
   348  	ModTime(context.Context) time.Time
   349  
   350  	// Size returns the size of the file
   351  	Size() int64
   352  }
   353  
   354  // Directory is a filesystem like directory provided by an Fs
   355  type Directory interface {
   356  	DirEntry
   357  
   358  	// Items returns the count of items in this directory or this
   359  	// directory and subdirectories if known, -1 for unknown
   360  	Items() int64
   361  
   362  	// ID returns the internal ID of this directory if known, or
   363  	// "" otherwise
   364  	ID() string
   365  }
   366  
   367  // MimeTyper is an optional interface for Object
   368  type MimeTyper interface {
   369  	// MimeType returns the content type of the Object if
   370  	// known, or "" if not
   371  	MimeType(ctx context.Context) string
   372  }
   373  
   374  // IDer is an optional interface for Object
   375  type IDer interface {
   376  	// ID returns the ID of the Object if known, or "" if not
   377  	ID() string
   378  }
   379  
   380  // ObjectUnWrapper is an optional interface for Object
   381  type ObjectUnWrapper interface {
   382  	// UnWrap returns the Object that this Object is wrapping or
   383  	// nil if it isn't wrapping anything
   384  	UnWrap() Object
   385  }
   386  
   387  // SetTierer is an optional interface for Object
   388  type SetTierer interface {
   389  	// SetTier performs changing storage tier of the Object if
   390  	// multiple storage classes supported
   391  	SetTier(tier string) error
   392  }
   393  
   394  // GetTierer is an optional interface for Object
   395  type GetTierer interface {
   396  	// GetTier returns storage tier or class of the Object
   397  	GetTier() string
   398  }
   399  
   400  // ObjectOptionalInterfaces returns the names of supported and
   401  // unsupported optional interfaces for an Object
   402  func ObjectOptionalInterfaces(o Object) (supported, unsupported []string) {
   403  	store := func(ok bool, name string) {
   404  		if ok {
   405  			supported = append(supported, name)
   406  		} else {
   407  			unsupported = append(unsupported, name)
   408  		}
   409  	}
   410  
   411  	_, ok := o.(MimeTyper)
   412  	store(ok, "MimeType")
   413  
   414  	_, ok = o.(IDer)
   415  	store(ok, "ID")
   416  
   417  	_, ok = o.(ObjectUnWrapper)
   418  	store(ok, "UnWrap")
   419  
   420  	_, ok = o.(SetTierer)
   421  	store(ok, "SetTier")
   422  
   423  	_, ok = o.(GetTierer)
   424  	store(ok, "GetTier")
   425  
   426  	return supported, unsupported
   427  }
   428  
   429  // ListRCallback defines a callback function for ListR to use
   430  //
   431  // It is called for each tranche of entries read from the listing and
   432  // if it returns an error, the listing stops.
   433  type ListRCallback func(entries DirEntries) error
   434  
   435  // ListRFn is defines the call used to recursively list a directory
   436  type ListRFn func(ctx context.Context, dir string, callback ListRCallback) error
   437  
   438  // NewUsageValue makes a valid value
   439  func NewUsageValue(value int64) *int64 {
   440  	p := new(int64)
   441  	*p = value
   442  	return p
   443  }
   444  
   445  // Usage is returned by the About call
   446  //
   447  // If a value is nil then it isn't supported by that backend
   448  type Usage struct {
   449  	Total   *int64 `json:"total,omitempty"`   // quota of bytes that can be used
   450  	Used    *int64 `json:"used,omitempty"`    // bytes in use
   451  	Trashed *int64 `json:"trashed,omitempty"` // bytes in trash
   452  	Other   *int64 `json:"other,omitempty"`   // other usage eg gmail in drive
   453  	Free    *int64 `json:"free,omitempty"`    // bytes which can be uploaded before reaching the quota
   454  	Objects *int64 `json:"objects,omitempty"` // objects in the storage system
   455  }
   456  
   457  // WriterAtCloser wraps io.WriterAt and io.Closer
   458  type WriterAtCloser interface {
   459  	io.WriterAt
   460  	io.Closer
   461  }
   462  
   463  // Features describe the optional features of the Fs
   464  type Features struct {
   465  	// Feature flags, whether Fs
   466  	CaseInsensitive         bool // has case insensitive files
   467  	DuplicateFiles          bool // allows duplicate files
   468  	ReadMimeType            bool // can read the mime type of objects
   469  	WriteMimeType           bool // can set the mime type of objects
   470  	CanHaveEmptyDirectories bool // can have empty directories
   471  	BucketBased             bool // is bucket based (like s3, swift etc)
   472  	SetTier                 bool // allows set tier functionality on objects
   473  	GetTier                 bool // allows to retrieve storage tier of objects
   474  	ServerSideAcrossConfigs bool // can server side copy between different remotes of the same type
   475  
   476  	// Purge all files in the root and the root directory
   477  	//
   478  	// Implement this if you have a way of deleting all the files
   479  	// quicker than just running Remove() on the result of List()
   480  	//
   481  	// Return an error if it doesn't exist
   482  	Purge func(ctx context.Context) error
   483  
   484  	// Copy src to this remote using server side copy operations.
   485  	//
   486  	// This is stored with the remote path given
   487  	//
   488  	// It returns the destination Object and a possible error
   489  	//
   490  	// Will only be called if src.Fs().Name() == f.Name()
   491  	//
   492  	// If it isn't possible then return fs.ErrorCantCopy
   493  	Copy func(ctx context.Context, src Object, remote string) (Object, error)
   494  
   495  	// Move src to this remote using server side move operations.
   496  	//
   497  	// This is stored with the remote path given
   498  	//
   499  	// It returns the destination Object and a possible error
   500  	//
   501  	// Will only be called if src.Fs().Name() == f.Name()
   502  	//
   503  	// If it isn't possible then return fs.ErrorCantMove
   504  	Move func(ctx context.Context, src Object, remote string) (Object, error)
   505  
   506  	// DirMove moves src, srcRemote to this remote at dstRemote
   507  	// using server side move operations.
   508  	//
   509  	// Will only be called if src.Fs().Name() == f.Name()
   510  	//
   511  	// If it isn't possible then return fs.ErrorCantDirMove
   512  	//
   513  	// If destination exists then return fs.ErrorDirExists
   514  	DirMove func(ctx context.Context, src Fs, srcRemote, dstRemote string) error
   515  
   516  	// ChangeNotify calls the passed function with a path
   517  	// that has had changes. If the implementation
   518  	// uses polling, it should adhere to the given interval.
   519  	ChangeNotify func(context.Context, func(string, EntryType), <-chan time.Duration)
   520  
   521  	// UnWrap returns the Fs that this Fs is wrapping
   522  	UnWrap func() Fs
   523  
   524  	// WrapFs returns the Fs that is wrapping this Fs
   525  	WrapFs func() Fs
   526  
   527  	// SetWrapper sets the Fs that is wrapping this Fs
   528  	SetWrapper func(f Fs)
   529  
   530  	// DirCacheFlush resets the directory cache - used in testing
   531  	// as an optional interface
   532  	DirCacheFlush func()
   533  
   534  	// PublicLink generates a public link to the remote path (usually readable by anyone)
   535  	PublicLink func(ctx context.Context, remote string) (string, error)
   536  
   537  	// Put in to the remote path with the modTime given of the given size
   538  	//
   539  	// May create the object even if it returns an error - if so
   540  	// will return the object and the error, otherwise will return
   541  	// nil and the error
   542  	//
   543  	// May create duplicates or return errors if src already
   544  	// exists.
   545  	PutUnchecked func(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
   546  
   547  	// PutStream uploads to the remote path with the modTime given of indeterminate size
   548  	//
   549  	// May create the object even if it returns an error - if so
   550  	// will return the object and the error, otherwise will return
   551  	// nil and the error
   552  	PutStream func(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
   553  
   554  	// MergeDirs merges the contents of all the directories passed
   555  	// in into the first one and rmdirs the other directories.
   556  	MergeDirs func(ctx context.Context, dirs []Directory) error
   557  
   558  	// CleanUp the trash in the Fs
   559  	//
   560  	// Implement this if you have a way of emptying the trash or
   561  	// otherwise cleaning up old versions of files.
   562  	CleanUp func(ctx context.Context) error
   563  
   564  	// ListR lists the objects and directories of the Fs starting
   565  	// from dir recursively into out.
   566  	//
   567  	// dir should be "" to start from the root, and should not
   568  	// have trailing slashes.
   569  	//
   570  	// This should return ErrDirNotFound if the directory isn't
   571  	// found.
   572  	//
   573  	// It should call callback for each tranche of entries read.
   574  	// These need not be returned in any particular order.  If
   575  	// callback returns an error then the listing will stop
   576  	// immediately.
   577  	//
   578  	// Don't implement this unless you have a more efficient way
   579  	// of listing recursively that doing a directory traversal.
   580  	ListR ListRFn
   581  
   582  	// About gets quota information from the Fs
   583  	About func(ctx context.Context) (*Usage, error)
   584  
   585  	// OpenWriterAt opens with a handle for random access writes
   586  	//
   587  	// Pass in the remote desired and the size if known.
   588  	//
   589  	// It truncates any existing object
   590  	OpenWriterAt func(ctx context.Context, remote string, size int64) (WriterAtCloser, error)
   591  }
   592  
   593  // Disable nil's out the named feature.  If it isn't found then it
   594  // will log a message.
   595  func (ft *Features) Disable(name string) *Features {
   596  	v := reflect.ValueOf(ft).Elem()
   597  	vType := v.Type()
   598  	for i := 0; i < v.NumField(); i++ {
   599  		vName := vType.Field(i).Name
   600  		field := v.Field(i)
   601  		if strings.EqualFold(name, vName) {
   602  			if !field.CanSet() {
   603  				Errorf(nil, "Can't set Feature %q", name)
   604  			} else {
   605  				zero := reflect.Zero(field.Type())
   606  				field.Set(zero)
   607  				Debugf(nil, "Reset feature %q", name)
   608  			}
   609  		}
   610  	}
   611  	return ft
   612  }
   613  
   614  // List returns a slice of all the possible feature names
   615  func (ft *Features) List() (out []string) {
   616  	v := reflect.ValueOf(ft).Elem()
   617  	vType := v.Type()
   618  	for i := 0; i < v.NumField(); i++ {
   619  		out = append(out, vType.Field(i).Name)
   620  	}
   621  	return out
   622  }
   623  
   624  // Enabled returns a map of features with keys showing whether they
   625  // are enabled or not
   626  func (ft *Features) Enabled() (features map[string]bool) {
   627  	v := reflect.ValueOf(ft).Elem()
   628  	vType := v.Type()
   629  	features = make(map[string]bool, v.NumField())
   630  	for i := 0; i < v.NumField(); i++ {
   631  		vName := vType.Field(i).Name
   632  		field := v.Field(i)
   633  		if field.Kind() == reflect.Func {
   634  			// Can't compare functions
   635  			features[vName] = !field.IsNil()
   636  		} else {
   637  			zero := reflect.Zero(field.Type())
   638  			features[vName] = field.Interface() != zero.Interface()
   639  		}
   640  	}
   641  	return features
   642  }
   643  
   644  // DisableList nil's out the comma separated list of named features.
   645  // If it isn't found then it will log a message.
   646  func (ft *Features) DisableList(list []string) *Features {
   647  	for _, feature := range list {
   648  		ft.Disable(strings.TrimSpace(feature))
   649  	}
   650  	return ft
   651  }
   652  
   653  // Fill fills in the function pointers in the Features struct from the
   654  // optional interfaces.  It returns the original updated Features
   655  // struct passed in.
   656  func (ft *Features) Fill(f Fs) *Features {
   657  	if do, ok := f.(Purger); ok {
   658  		ft.Purge = do.Purge
   659  	}
   660  	if do, ok := f.(Copier); ok {
   661  		ft.Copy = do.Copy
   662  	}
   663  	if do, ok := f.(Mover); ok {
   664  		ft.Move = do.Move
   665  	}
   666  	if do, ok := f.(DirMover); ok {
   667  		ft.DirMove = do.DirMove
   668  	}
   669  	if do, ok := f.(ChangeNotifier); ok {
   670  		ft.ChangeNotify = do.ChangeNotify
   671  	}
   672  	if do, ok := f.(UnWrapper); ok {
   673  		ft.UnWrap = do.UnWrap
   674  	}
   675  	if do, ok := f.(Wrapper); ok {
   676  		ft.WrapFs = do.WrapFs
   677  		ft.SetWrapper = do.SetWrapper
   678  	}
   679  	if do, ok := f.(DirCacheFlusher); ok {
   680  		ft.DirCacheFlush = do.DirCacheFlush
   681  	}
   682  	if do, ok := f.(PublicLinker); ok {
   683  		ft.PublicLink = do.PublicLink
   684  	}
   685  	if do, ok := f.(PutUncheckeder); ok {
   686  		ft.PutUnchecked = do.PutUnchecked
   687  	}
   688  	if do, ok := f.(PutStreamer); ok {
   689  		ft.PutStream = do.PutStream
   690  	}
   691  	if do, ok := f.(MergeDirser); ok {
   692  		ft.MergeDirs = do.MergeDirs
   693  	}
   694  	if do, ok := f.(CleanUpper); ok {
   695  		ft.CleanUp = do.CleanUp
   696  	}
   697  	if do, ok := f.(ListRer); ok {
   698  		ft.ListR = do.ListR
   699  	}
   700  	if do, ok := f.(Abouter); ok {
   701  		ft.About = do.About
   702  	}
   703  	if do, ok := f.(OpenWriterAter); ok {
   704  		ft.OpenWriterAt = do.OpenWriterAt
   705  	}
   706  	return ft.DisableList(Config.DisableFeatures)
   707  }
   708  
   709  // Mask the Features with the Fs passed in
   710  //
   711  // Only optional features which are implemented in both the original
   712  // Fs AND the one passed in will be advertised.  Any features which
   713  // aren't in both will be set to false/nil, except for UnWrap/Wrap which
   714  // will be left untouched.
   715  func (ft *Features) Mask(f Fs) *Features {
   716  	mask := f.Features()
   717  	ft.CaseInsensitive = ft.CaseInsensitive && mask.CaseInsensitive
   718  	ft.DuplicateFiles = ft.DuplicateFiles && mask.DuplicateFiles
   719  	ft.ReadMimeType = ft.ReadMimeType && mask.ReadMimeType
   720  	ft.WriteMimeType = ft.WriteMimeType && mask.WriteMimeType
   721  	ft.CanHaveEmptyDirectories = ft.CanHaveEmptyDirectories && mask.CanHaveEmptyDirectories
   722  	ft.BucketBased = ft.BucketBased && mask.BucketBased
   723  	ft.SetTier = ft.SetTier && mask.SetTier
   724  	ft.GetTier = ft.GetTier && mask.GetTier
   725  
   726  	if mask.Purge == nil {
   727  		ft.Purge = nil
   728  	}
   729  	if mask.Copy == nil {
   730  		ft.Copy = nil
   731  	}
   732  	if mask.Move == nil {
   733  		ft.Move = nil
   734  	}
   735  	if mask.DirMove == nil {
   736  		ft.DirMove = nil
   737  	}
   738  	if mask.ChangeNotify == nil {
   739  		ft.ChangeNotify = nil
   740  	}
   741  	// if mask.UnWrap == nil {
   742  	// 	ft.UnWrap = nil
   743  	// }
   744  	// if mask.Wrapper == nil {
   745  	// 	ft.Wrapper = nil
   746  	// }
   747  	if mask.DirCacheFlush == nil {
   748  		ft.DirCacheFlush = nil
   749  	}
   750  	if mask.PublicLink == nil {
   751  		ft.PublicLink = nil
   752  	}
   753  	if mask.PutUnchecked == nil {
   754  		ft.PutUnchecked = nil
   755  	}
   756  	if mask.PutStream == nil {
   757  		ft.PutStream = nil
   758  	}
   759  	if mask.MergeDirs == nil {
   760  		ft.MergeDirs = nil
   761  	}
   762  	if mask.CleanUp == nil {
   763  		ft.CleanUp = nil
   764  	}
   765  	if mask.ListR == nil {
   766  		ft.ListR = nil
   767  	}
   768  	if mask.About == nil {
   769  		ft.About = nil
   770  	}
   771  	if mask.OpenWriterAt == nil {
   772  		ft.OpenWriterAt = nil
   773  	}
   774  	return ft.DisableList(Config.DisableFeatures)
   775  }
   776  
   777  // Wrap makes a Copy of the features passed in, overriding the UnWrap/Wrap
   778  // method only if available in f.
   779  func (ft *Features) Wrap(f Fs) *Features {
   780  	ftCopy := new(Features)
   781  	*ftCopy = *ft
   782  	if do, ok := f.(UnWrapper); ok {
   783  		ftCopy.UnWrap = do.UnWrap
   784  	}
   785  	if do, ok := f.(Wrapper); ok {
   786  		ftCopy.WrapFs = do.WrapFs
   787  		ftCopy.SetWrapper = do.SetWrapper
   788  	}
   789  	return ftCopy
   790  }
   791  
   792  // WrapsFs adds extra information between `f` which wraps `w`
   793  func (ft *Features) WrapsFs(f Fs, w Fs) *Features {
   794  	wFeatures := w.Features()
   795  	if wFeatures.WrapFs != nil && wFeatures.SetWrapper != nil {
   796  		wFeatures.SetWrapper(f)
   797  	}
   798  	return ft
   799  }
   800  
   801  // Purger is an optional interfaces for Fs
   802  type Purger interface {
   803  	// Purge all files in the root and the root directory
   804  	//
   805  	// Implement this if you have a way of deleting all the files
   806  	// quicker than just running Remove() on the result of List()
   807  	//
   808  	// Return an error if it doesn't exist
   809  	Purge(ctx context.Context) error
   810  }
   811  
   812  // Copier is an optional interface for Fs
   813  type Copier interface {
   814  	// Copy src to this remote using server side copy operations.
   815  	//
   816  	// This is stored with the remote path given
   817  	//
   818  	// It returns the destination Object and a possible error
   819  	//
   820  	// Will only be called if src.Fs().Name() == f.Name()
   821  	//
   822  	// If it isn't possible then return fs.ErrorCantCopy
   823  	Copy(ctx context.Context, src Object, remote string) (Object, error)
   824  }
   825  
   826  // Mover is an optional interface for Fs
   827  type Mover interface {
   828  	// Move src to this remote using server side move operations.
   829  	//
   830  	// This is stored with the remote path given
   831  	//
   832  	// It returns the destination Object and a possible error
   833  	//
   834  	// Will only be called if src.Fs().Name() == f.Name()
   835  	//
   836  	// If it isn't possible then return fs.ErrorCantMove
   837  	Move(ctx context.Context, src Object, remote string) (Object, error)
   838  }
   839  
   840  // DirMover is an optional interface for Fs
   841  type DirMover interface {
   842  	// DirMove moves src, srcRemote to this remote at dstRemote
   843  	// using server side move operations.
   844  	//
   845  	// Will only be called if src.Fs().Name() == f.Name()
   846  	//
   847  	// If it isn't possible then return fs.ErrorCantDirMove
   848  	//
   849  	// If destination exists then return fs.ErrorDirExists
   850  	DirMove(ctx context.Context, src Fs, srcRemote, dstRemote string) error
   851  }
   852  
   853  // ChangeNotifier is an optional interface for Fs
   854  type ChangeNotifier interface {
   855  	// ChangeNotify calls the passed function with a path
   856  	// that has had changes. If the implementation
   857  	// uses polling, it should adhere to the given interval.
   858  	// At least one value will be written to the channel,
   859  	// specifying the initial value and updated values might
   860  	// follow. A 0 Duration should pause the polling.
   861  	// The ChangeNotify implementation must empty the channel
   862  	// regularly. When the channel gets closed, the implementation
   863  	// should stop polling and release resources.
   864  	ChangeNotify(context.Context, func(string, EntryType), <-chan time.Duration)
   865  }
   866  
   867  // UnWrapper is an optional interfaces for Fs
   868  type UnWrapper interface {
   869  	// UnWrap returns the Fs that this Fs is wrapping
   870  	UnWrap() Fs
   871  }
   872  
   873  // Wrapper is an optional interfaces for Fs
   874  type Wrapper interface {
   875  	// Wrap returns the Fs that is wrapping this Fs
   876  	WrapFs() Fs
   877  	// SetWrapper sets the Fs that is wrapping this Fs
   878  	SetWrapper(f Fs)
   879  }
   880  
   881  // DirCacheFlusher is an optional interface for Fs
   882  type DirCacheFlusher interface {
   883  	// DirCacheFlush resets the directory cache - used in testing
   884  	// as an optional interface
   885  	DirCacheFlush()
   886  }
   887  
   888  // PutUncheckeder is an optional interface for Fs
   889  type PutUncheckeder interface {
   890  	// Put in to the remote path with the modTime given of the given size
   891  	//
   892  	// May create the object even if it returns an error - if so
   893  	// will return the object and the error, otherwise will return
   894  	// nil and the error
   895  	//
   896  	// May create duplicates or return errors if src already
   897  	// exists.
   898  	PutUnchecked(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
   899  }
   900  
   901  // PutStreamer is an optional interface for Fs
   902  type PutStreamer interface {
   903  	// PutStream uploads to the remote path with the modTime given of indeterminate size
   904  	//
   905  	// May create the object even if it returns an error - if so
   906  	// will return the object and the error, otherwise will return
   907  	// nil and the error
   908  	PutStream(ctx context.Context, in io.Reader, src ObjectInfo, options ...OpenOption) (Object, error)
   909  }
   910  
   911  // PublicLinker is an optional interface for Fs
   912  type PublicLinker interface {
   913  	// PublicLink generates a public link to the remote path (usually readable by anyone)
   914  	PublicLink(ctx context.Context, remote string) (string, error)
   915  }
   916  
   917  // MergeDirser is an option interface for Fs
   918  type MergeDirser interface {
   919  	// MergeDirs merges the contents of all the directories passed
   920  	// in into the first one and rmdirs the other directories.
   921  	MergeDirs(ctx context.Context, dirs []Directory) error
   922  }
   923  
   924  // CleanUpper is an optional interfaces for Fs
   925  type CleanUpper interface {
   926  	// CleanUp the trash in the Fs
   927  	//
   928  	// Implement this if you have a way of emptying the trash or
   929  	// otherwise cleaning up old versions of files.
   930  	CleanUp(ctx context.Context) error
   931  }
   932  
   933  // ListRer is an optional interfaces for Fs
   934  type ListRer interface {
   935  	// ListR lists the objects and directories of the Fs starting
   936  	// from dir recursively into out.
   937  	//
   938  	// dir should be "" to start from the root, and should not
   939  	// have trailing slashes.
   940  	//
   941  	// This should return ErrDirNotFound if the directory isn't
   942  	// found.
   943  	//
   944  	// It should call callback for each tranche of entries read.
   945  	// These need not be returned in any particular order.  If
   946  	// callback returns an error then the listing will stop
   947  	// immediately.
   948  	//
   949  	// Don't implement this unless you have a more efficient way
   950  	// of listing recursively that doing a directory traversal.
   951  	ListR(ctx context.Context, dir string, callback ListRCallback) error
   952  }
   953  
   954  // RangeSeeker is the interface that wraps the RangeSeek method.
   955  //
   956  // Some of the returns from Object.Open() may optionally implement
   957  // this method for efficiency purposes.
   958  type RangeSeeker interface {
   959  	// RangeSeek behaves like a call to Seek(offset int64, whence
   960  	// int) with the output wrapped in an io.LimitedReader
   961  	// limiting the total length to limit.
   962  	//
   963  	// RangeSeek with a limit of < 0 is equivalent to a regular Seek.
   964  	RangeSeek(ctx context.Context, offset int64, whence int, length int64) (int64, error)
   965  }
   966  
   967  // Abouter is an optional interface for Fs
   968  type Abouter interface {
   969  	// About gets quota information from the Fs
   970  	About(ctx context.Context) (*Usage, error)
   971  }
   972  
   973  // OpenWriterAter is an optional interface for Fs
   974  type OpenWriterAter interface {
   975  	// OpenWriterAt opens with a handle for random access writes
   976  	//
   977  	// Pass in the remote desired and the size if known.
   978  	//
   979  	// It truncates any existing object
   980  	OpenWriterAt(ctx context.Context, remote string, size int64) (WriterAtCloser, error)
   981  }
   982  
   983  // ObjectsChan is a channel of Objects
   984  type ObjectsChan chan Object
   985  
   986  // Objects is a slice of Object~s
   987  type Objects []Object
   988  
   989  // ObjectPair is a pair of Objects used to describe a potential copy
   990  // operation.
   991  type ObjectPair struct {
   992  	Src, Dst Object
   993  }
   994  
   995  // Find looks for an RegInfo object for the name passed in.  The name
   996  // can be either the Name or the Prefix.
   997  //
   998  // Services are looked up in the config file
   999  func Find(name string) (*RegInfo, error) {
  1000  	for _, item := range Registry {
  1001  		if item.Name == name || item.Prefix == name || item.FileName() == name {
  1002  			return item, nil
  1003  		}
  1004  	}
  1005  	return nil, errors.Errorf("didn't find backend called %q", name)
  1006  }
  1007  
  1008  // MustFind looks for an Info object for the type name passed in
  1009  //
  1010  // Services are looked up in the config file
  1011  //
  1012  // Exits with a fatal error if not found
  1013  func MustFind(name string) *RegInfo {
  1014  	fs, err := Find(name)
  1015  	if err != nil {
  1016  		log.Fatalf("Failed to find remote: %v", err)
  1017  	}
  1018  	return fs
  1019  }
  1020  
  1021  // ParseRemote deconstructs a path into configName, fsPath, looking up
  1022  // the fsName in the config file (returning NotFoundInConfigFile if not found)
  1023  func ParseRemote(path string) (fsInfo *RegInfo, configName, fsPath string, err error) {
  1024  	configName, fsPath = fspath.Parse(path)
  1025  	var fsName string
  1026  	var ok bool
  1027  	if configName != "" {
  1028  		if strings.HasPrefix(configName, ":") {
  1029  			fsName = configName[1:]
  1030  		} else {
  1031  			m := ConfigMap(nil, configName)
  1032  			fsName, ok = m.Get("type")
  1033  			if !ok {
  1034  				return nil, "", "", ErrorNotFoundInConfigFile
  1035  			}
  1036  		}
  1037  	} else {
  1038  		fsName = "local"
  1039  		configName = "local"
  1040  	}
  1041  	fsInfo, err = Find(fsName)
  1042  	return fsInfo, configName, fsPath, err
  1043  }
  1044  
  1045  // A configmap.Getter to read from the environment RCLONE_CONFIG_backend_option_name
  1046  type configEnvVars string
  1047  
  1048  // Get a config item from the environment variables if possible
  1049  func (configName configEnvVars) Get(key string) (value string, ok bool) {
  1050  	return os.LookupEnv(ConfigToEnv(string(configName), key))
  1051  }
  1052  
  1053  // A configmap.Getter to read from the environment RCLONE_option_name
  1054  type optionEnvVars string
  1055  
  1056  // Get a config item from the option environment variables if possible
  1057  func (prefix optionEnvVars) Get(key string) (value string, ok bool) {
  1058  	return os.LookupEnv(OptionToEnv(string(prefix) + "-" + key))
  1059  }
  1060  
  1061  // A configmap.Getter to read either the default value or the set
  1062  // value from the RegInfo.Options
  1063  type regInfoValues struct {
  1064  	fsInfo     *RegInfo
  1065  	useDefault bool
  1066  }
  1067  
  1068  // override the values in configMap with the either the flag values or
  1069  // the default values
  1070  func (r *regInfoValues) Get(key string) (value string, ok bool) {
  1071  	for i := range r.fsInfo.Options {
  1072  		o := &r.fsInfo.Options[i]
  1073  		if o.Name == key {
  1074  			if r.useDefault || o.Value != nil {
  1075  				return o.String(), true
  1076  			}
  1077  			break
  1078  		}
  1079  	}
  1080  	return "", false
  1081  }
  1082  
  1083  // A configmap.Setter to read from the config file
  1084  type setConfigFile string
  1085  
  1086  // Set a config item into the config file
  1087  func (section setConfigFile) Set(key, value string) {
  1088  	Debugf(nil, "Saving config %q = %q in section %q of the config file", key, value, section)
  1089  	ConfigFileSet(string(section), key, value)
  1090  }
  1091  
  1092  // A configmap.Getter to read from the config file
  1093  type getConfigFile string
  1094  
  1095  // Get a config item from the config file
  1096  func (section getConfigFile) Get(key string) (value string, ok bool) {
  1097  	value, ok = ConfigFileGet(string(section), key)
  1098  	// Ignore empty lines in the config file
  1099  	if value == "" {
  1100  		ok = false
  1101  	}
  1102  	return value, ok
  1103  }
  1104  
  1105  // ConfigMap creates a configmap.Map from the *RegInfo and the
  1106  // configName passed in.
  1107  //
  1108  // If fsInfo is nil then the returned configmap.Map should only be
  1109  // used for reading non backend specific parameters, such as "type".
  1110  func ConfigMap(fsInfo *RegInfo, configName string) (config *configmap.Map) {
  1111  	// Create the config
  1112  	config = configmap.New()
  1113  
  1114  	// Read the config, more specific to least specific
  1115  
  1116  	// flag values
  1117  	if fsInfo != nil {
  1118  		config.AddGetter(&regInfoValues{fsInfo, false})
  1119  	}
  1120  
  1121  	// remote specific environment vars
  1122  	config.AddGetter(configEnvVars(configName))
  1123  
  1124  	// backend specific environment vars
  1125  	if fsInfo != nil {
  1126  		config.AddGetter(optionEnvVars(fsInfo.Prefix))
  1127  	}
  1128  
  1129  	// config file
  1130  	config.AddGetter(getConfigFile(configName))
  1131  
  1132  	// default values
  1133  	if fsInfo != nil {
  1134  		config.AddGetter(&regInfoValues{fsInfo, true})
  1135  	}
  1136  
  1137  	// Set Config
  1138  	config.AddSetter(setConfigFile(configName))
  1139  	return config
  1140  }
  1141  
  1142  // ConfigFs makes the config for calling NewFs with.
  1143  //
  1144  // It parses the path which is of the form remote:path
  1145  //
  1146  // Remotes are looked up in the config file.  If the remote isn't
  1147  // found then NotFoundInConfigFile will be returned.
  1148  func ConfigFs(path string) (fsInfo *RegInfo, configName, fsPath string, config *configmap.Map, err error) {
  1149  	// Parse the remote path
  1150  	fsInfo, configName, fsPath, err = ParseRemote(path)
  1151  	if err != nil {
  1152  		return
  1153  	}
  1154  	config = ConfigMap(fsInfo, configName)
  1155  	return
  1156  }
  1157  
  1158  // NewFs makes a new Fs object from the path
  1159  //
  1160  // The path is of the form remote:path
  1161  //
  1162  // Remotes are looked up in the config file.  If the remote isn't
  1163  // found then NotFoundInConfigFile will be returned.
  1164  //
  1165  // On Windows avoid single character remote names as they can be mixed
  1166  // up with drive letters.
  1167  func NewFs(path string) (Fs, error) {
  1168  	fsInfo, configName, fsPath, config, err := ConfigFs(path)
  1169  	if err != nil {
  1170  		return nil, err
  1171  	}
  1172  	return fsInfo.NewFs(configName, fsPath, config)
  1173  }
  1174  
  1175  // TemporaryLocalFs creates a local FS in the OS's temporary directory.
  1176  //
  1177  // No cleanup is performed, the caller must call Purge on the Fs themselves.
  1178  func TemporaryLocalFs() (Fs, error) {
  1179  	path, err := ioutil.TempDir("", "rclone-spool")
  1180  	if err == nil {
  1181  		err = os.Remove(path)
  1182  	}
  1183  	if err != nil {
  1184  		return nil, err
  1185  	}
  1186  	path = filepath.ToSlash(path)
  1187  	return NewFs(path)
  1188  }
  1189  
  1190  // CheckClose is a utility function used to check the return from
  1191  // Close in a defer statement.
  1192  func CheckClose(c io.Closer, err *error) {
  1193  	cerr := c.Close()
  1194  	if *err == nil {
  1195  		*err = cerr
  1196  	}
  1197  }
  1198  
  1199  // FileExists returns true if a file remote exists.
  1200  // If remote is a directory, FileExists returns false.
  1201  func FileExists(ctx context.Context, fs Fs, remote string) (bool, error) {
  1202  	_, err := fs.NewObject(ctx, remote)
  1203  	if err != nil {
  1204  		if err == ErrorObjectNotFound || err == ErrorNotAFile || err == ErrorPermissionDenied {
  1205  			return false, nil
  1206  		}
  1207  		return false, err
  1208  	}
  1209  	return true, nil
  1210  }
  1211  
  1212  // GetModifyWindow calculates the maximum modify window between the given Fses
  1213  // and the Config.ModifyWindow parameter.
  1214  func GetModifyWindow(fss ...Info) time.Duration {
  1215  	window := Config.ModifyWindow
  1216  	for _, f := range fss {
  1217  		if f != nil {
  1218  			precision := f.Precision()
  1219  			if precision == ModTimeNotSupported {
  1220  				return ModTimeNotSupported
  1221  			}
  1222  			if precision > window {
  1223  				window = precision
  1224  			}
  1225  		}
  1226  	}
  1227  	return window
  1228  }
  1229  
  1230  // Pacer is a simple wrapper around a pacer.Pacer with logging.
  1231  type Pacer struct {
  1232  	*pacer.Pacer
  1233  }
  1234  
  1235  type logCalculator struct {
  1236  	pacer.Calculator
  1237  }
  1238  
  1239  // NewPacer creates a Pacer for the given Fs and Calculator.
  1240  func NewPacer(c pacer.Calculator) *Pacer {
  1241  	p := &Pacer{
  1242  		Pacer: pacer.New(
  1243  			pacer.InvokerOption(pacerInvoker),
  1244  			pacer.MaxConnectionsOption(Config.Checkers+Config.Transfers),
  1245  			pacer.RetriesOption(Config.LowLevelRetries),
  1246  			pacer.CalculatorOption(c),
  1247  		),
  1248  	}
  1249  	p.SetCalculator(c)
  1250  	return p
  1251  }
  1252  
  1253  func (d *logCalculator) Calculate(state pacer.State) time.Duration {
  1254  	oldSleepTime := state.SleepTime
  1255  	newSleepTime := d.Calculator.Calculate(state)
  1256  	if state.ConsecutiveRetries > 0 {
  1257  		if newSleepTime != oldSleepTime {
  1258  			Debugf("pacer", "Rate limited, increasing sleep to %v", newSleepTime)
  1259  		}
  1260  	} else {
  1261  		if newSleepTime != oldSleepTime {
  1262  			Debugf("pacer", "Reducing sleep to %v", newSleepTime)
  1263  		}
  1264  	}
  1265  	return newSleepTime
  1266  }
  1267  
  1268  // SetCalculator sets the pacing algorithm. Don't modify the Calculator object
  1269  // afterwards, use the ModifyCalculator method when needed.
  1270  //
  1271  // It will choose the default algorithm if nil is passed in.
  1272  func (p *Pacer) SetCalculator(c pacer.Calculator) {
  1273  	switch c.(type) {
  1274  	case *logCalculator:
  1275  		Logf("pacer", "Invalid Calculator in fs.Pacer.SetCalculator")
  1276  	case nil:
  1277  		c = &logCalculator{pacer.NewDefault()}
  1278  	default:
  1279  		c = &logCalculator{c}
  1280  	}
  1281  
  1282  	p.Pacer.SetCalculator(c)
  1283  }
  1284  
  1285  // ModifyCalculator calls the given function with the currently configured
  1286  // Calculator and the Pacer lock held.
  1287  func (p *Pacer) ModifyCalculator(f func(pacer.Calculator)) {
  1288  	p.ModifyCalculator(func(c pacer.Calculator) {
  1289  		switch _c := c.(type) {
  1290  		case *logCalculator:
  1291  			f(_c.Calculator)
  1292  		default:
  1293  			Logf("pacer", "Invalid Calculator in fs.Pacer: %t", c)
  1294  			f(c)
  1295  		}
  1296  	})
  1297  }
  1298  
  1299  func pacerInvoker(try, retries int, f pacer.Paced) (retry bool, err error) {
  1300  	retry, err = f()
  1301  	if retry {
  1302  		Debugf("pacer", "low level retry %d/%d (error %v)", try, retries, err)
  1303  		err = fserrors.RetryError(err)
  1304  	}
  1305  	return
  1306  }