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(®InfoValues{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(®InfoValues{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 }