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

     1  // Package local provides a filesystem interface
     2  package local
     3  
     4  import (
     5  	"bytes"
     6  	"context"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"os"
    11  	"path"
    12  	"path/filepath"
    13  	"regexp"
    14  	"runtime"
    15  	"strings"
    16  	"sync"
    17  	"time"
    18  	"unicode/utf8"
    19  
    20  	"github.com/ncw/rclone/fs"
    21  	"github.com/ncw/rclone/fs/accounting"
    22  	"github.com/ncw/rclone/fs/config/configmap"
    23  	"github.com/ncw/rclone/fs/config/configstruct"
    24  	"github.com/ncw/rclone/fs/fserrors"
    25  	"github.com/ncw/rclone/fs/hash"
    26  	"github.com/ncw/rclone/lib/file"
    27  	"github.com/ncw/rclone/lib/readers"
    28  	"github.com/pkg/errors"
    29  )
    30  
    31  // Constants
    32  const devUnset = 0xdeadbeefcafebabe                                       // a device id meaning it is unset
    33  const linkSuffix = ".rclonelink"                                          // The suffix added to a translated symbolic link
    34  const useReadDir = (runtime.GOOS == "windows" || runtime.GOOS == "plan9") // these OSes read FileInfos directly
    35  
    36  // Register with Fs
    37  func init() {
    38  	fsi := &fs.RegInfo{
    39  		Name:        "local",
    40  		Description: "Local Disk",
    41  		NewFs:       NewFs,
    42  		Options: []fs.Option{{
    43  			Name: "nounc",
    44  			Help: "Disable UNC (long path names) conversion on Windows",
    45  			Examples: []fs.OptionExample{{
    46  				Value: "true",
    47  				Help:  "Disables long file names",
    48  			}},
    49  		}, {
    50  			Name:     "copy_links",
    51  			Help:     "Follow symlinks and copy the pointed to item.",
    52  			Default:  false,
    53  			NoPrefix: true,
    54  			ShortOpt: "L",
    55  			Advanced: true,
    56  		}, {
    57  			Name:     "links",
    58  			Help:     "Translate symlinks to/from regular files with a '" + linkSuffix + "' extension",
    59  			Default:  false,
    60  			NoPrefix: true,
    61  			ShortOpt: "l",
    62  			Advanced: true,
    63  		}, {
    64  			Name: "skip_links",
    65  			Help: `Don't warn about skipped symlinks.
    66  This flag disables warning messages on skipped symlinks or junction
    67  points, as you explicitly acknowledge that they should be skipped.`,
    68  			Default:  false,
    69  			NoPrefix: true,
    70  			Advanced: true,
    71  		}, {
    72  			Name: "no_unicode_normalization",
    73  			Help: `Don't apply unicode normalization to paths and filenames (Deprecated)
    74  
    75  This flag is deprecated now.  Rclone no longer normalizes unicode file
    76  names, but it compares them with unicode normalization in the sync
    77  routine instead.`,
    78  			Default:  false,
    79  			Advanced: true,
    80  		}, {
    81  			Name: "no_check_updated",
    82  			Help: `Don't check to see if the files change during upload
    83  
    84  Normally rclone checks the size and modification time of files as they
    85  are being uploaded and aborts with a message which starts "can't copy
    86  - source file is being updated" if the file changes during upload.
    87  
    88  However on some file systems this modification time check may fail (eg
    89  [Glusterfs #2206](https://github.com/ncw/rclone/issues/2206)) so this
    90  check can be disabled with this flag.`,
    91  			Default:  false,
    92  			Advanced: true,
    93  		}, {
    94  			Name:     "one_file_system",
    95  			Help:     "Don't cross filesystem boundaries (unix/macOS only).",
    96  			Default:  false,
    97  			NoPrefix: true,
    98  			ShortOpt: "x",
    99  			Advanced: true,
   100  		}, {
   101  			Name: "case_sensitive",
   102  			Help: `Force the filesystem to report itself as case sensitive.
   103  
   104  Normally the local backend declares itself as case insensitive on
   105  Windows/macOS and case sensitive for everything else.  Use this flag
   106  to override the default choice.`,
   107  			Default:  false,
   108  			Advanced: true,
   109  		}, {
   110  			Name: "case_insensitive",
   111  			Help: `Force the filesystem to report itself as case insensitive
   112  
   113  Normally the local backend declares itself as case insensitive on
   114  Windows/macOS and case sensitive for everything else.  Use this flag
   115  to override the default choice.`,
   116  			Default:  false,
   117  			Advanced: true,
   118  		}},
   119  	}
   120  	fs.Register(fsi)
   121  }
   122  
   123  // Options defines the configuration for this backend
   124  type Options struct {
   125  	FollowSymlinks    bool `config:"copy_links"`
   126  	TranslateSymlinks bool `config:"links"`
   127  	SkipSymlinks      bool `config:"skip_links"`
   128  	NoUTFNorm         bool `config:"no_unicode_normalization"`
   129  	NoCheckUpdated    bool `config:"no_check_updated"`
   130  	NoUNC             bool `config:"nounc"`
   131  	OneFileSystem     bool `config:"one_file_system"`
   132  	CaseSensitive     bool `config:"case_sensitive"`
   133  	CaseInsensitive   bool `config:"case_insensitive"`
   134  }
   135  
   136  // Fs represents a local filesystem rooted at root
   137  type Fs struct {
   138  	name        string              // the name of the remote
   139  	root        string              // The root directory (OS path)
   140  	opt         Options             // parsed config options
   141  	features    *fs.Features        // optional features
   142  	dev         uint64              // device number of root node
   143  	precisionOk sync.Once           // Whether we need to read the precision
   144  	precision   time.Duration       // precision of local filesystem
   145  	wmu         sync.Mutex          // used for locking access to 'warned'.
   146  	warned      map[string]struct{} // whether we have warned about this string
   147  	// do os.Lstat or os.Stat
   148  	lstat          func(name string) (os.FileInfo, error)
   149  	dirNames       *mapper    // directory name mapping
   150  	objectHashesMu sync.Mutex // global lock for Object.hashes
   151  }
   152  
   153  // Object represents a local filesystem object
   154  type Object struct {
   155  	fs             *Fs    // The Fs this object is part of
   156  	remote         string // The remote path - properly UTF-8 encoded - for rclone
   157  	path           string // The local path - may not be properly UTF-8 encoded - for OS
   158  	size           int64  // file metadata - always present
   159  	mode           os.FileMode
   160  	modTime        time.Time
   161  	hashes         map[hash.Type]string // Hashes
   162  	translatedLink bool                 // Is this object a translated link
   163  }
   164  
   165  // ------------------------------------------------------------
   166  
   167  var errLinksAndCopyLinks = errors.New("can't use -l/--links with -L/--copy-links")
   168  
   169  // NewFs constructs an Fs from the path
   170  func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) {
   171  	// Parse config into Options struct
   172  	opt := new(Options)
   173  	err := configstruct.Set(m, opt)
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  	if opt.TranslateSymlinks && opt.FollowSymlinks {
   178  		return nil, errLinksAndCopyLinks
   179  	}
   180  
   181  	if opt.NoUTFNorm {
   182  		fs.Errorf(nil, "The --local-no-unicode-normalization flag is deprecated and will be removed")
   183  	}
   184  
   185  	f := &Fs{
   186  		name:     name,
   187  		opt:      *opt,
   188  		warned:   make(map[string]struct{}),
   189  		dev:      devUnset,
   190  		lstat:    os.Lstat,
   191  		dirNames: newMapper(),
   192  	}
   193  	f.root = f.cleanPath(root)
   194  	f.features = (&fs.Features{
   195  		CaseInsensitive:         f.caseInsensitive(),
   196  		CanHaveEmptyDirectories: true,
   197  	}).Fill(f)
   198  	if opt.FollowSymlinks {
   199  		f.lstat = os.Stat
   200  	}
   201  
   202  	// Check to see if this points to a file
   203  	fi, err := f.lstat(f.root)
   204  	if err == nil {
   205  		f.dev = readDevice(fi, f.opt.OneFileSystem)
   206  	}
   207  	if err == nil && f.isRegular(fi.Mode()) {
   208  		// It is a file, so use the parent as the root
   209  		f.root = filepath.Dir(f.root)
   210  		// return an error with an fs which points to the parent
   211  		return f, fs.ErrorIsFile
   212  	}
   213  	return f, nil
   214  }
   215  
   216  // Determine whether a file is a 'regular' file,
   217  // Symlinks are regular files, only if the TranslateSymlink
   218  // option is in-effect
   219  func (f *Fs) isRegular(mode os.FileMode) bool {
   220  	if !f.opt.TranslateSymlinks {
   221  		return mode.IsRegular()
   222  	}
   223  
   224  	// fi.Mode().IsRegular() tests that all mode bits are zero
   225  	// Since symlinks are accepted, test that all other bits are zero,
   226  	// except the symlink bit
   227  	return mode&os.ModeType&^os.ModeSymlink == 0
   228  }
   229  
   230  // Name of the remote (as passed into NewFs)
   231  func (f *Fs) Name() string {
   232  	return f.name
   233  }
   234  
   235  // Root of the remote (as passed into NewFs)
   236  func (f *Fs) Root() string {
   237  	return f.root
   238  }
   239  
   240  // String converts this Fs to a string
   241  func (f *Fs) String() string {
   242  	return fmt.Sprintf("Local file system at %s", f.root)
   243  }
   244  
   245  // Features returns the optional features of this Fs
   246  func (f *Fs) Features() *fs.Features {
   247  	return f.features
   248  }
   249  
   250  // caseInsensitive returns whether the remote is case insensitive or not
   251  func (f *Fs) caseInsensitive() bool {
   252  	if f.opt.CaseSensitive {
   253  		return false
   254  	}
   255  	if f.opt.CaseInsensitive {
   256  		return true
   257  	}
   258  	// FIXME not entirely accurate since you can have case
   259  	// sensitive Fses on darwin and case insensitive Fses on linux.
   260  	// Should probably check but that would involve creating a
   261  	// file in the remote to be most accurate which probably isn't
   262  	// desirable.
   263  	return runtime.GOOS == "windows" || runtime.GOOS == "darwin"
   264  }
   265  
   266  // translateLink checks whether the remote is a translated link
   267  // and returns a new path, removing the suffix as needed,
   268  // It also returns whether this is a translated link at all
   269  //
   270  // for regular files, dstPath is returned unchanged
   271  func translateLink(remote, dstPath string) (newDstPath string, isTranslatedLink bool) {
   272  	isTranslatedLink = strings.HasSuffix(remote, linkSuffix)
   273  	newDstPath = strings.TrimSuffix(dstPath, linkSuffix)
   274  	return newDstPath, isTranslatedLink
   275  }
   276  
   277  // newObject makes a half completed Object
   278  //
   279  // if dstPath is empty then it is made from remote
   280  func (f *Fs) newObject(remote, dstPath string) *Object {
   281  	translatedLink := false
   282  
   283  	if dstPath == "" {
   284  		dstPath = f.cleanPath(filepath.Join(f.root, remote))
   285  	}
   286  	remote = f.cleanRemote(remote)
   287  
   288  	if f.opt.TranslateSymlinks {
   289  		// Possibly receive a new name for dstPath
   290  		dstPath, translatedLink = translateLink(remote, dstPath)
   291  	}
   292  
   293  	return &Object{
   294  		fs:             f,
   295  		remote:         remote,
   296  		path:           dstPath,
   297  		translatedLink: translatedLink,
   298  	}
   299  }
   300  
   301  // Return an Object from a path
   302  //
   303  // May return nil if an error occurred
   304  func (f *Fs) newObjectWithInfo(remote, dstPath string, info os.FileInfo) (fs.Object, error) {
   305  	o := f.newObject(remote, dstPath)
   306  	if info != nil {
   307  		o.setMetadata(info)
   308  	} else {
   309  		err := o.lstat()
   310  		if err != nil {
   311  			if os.IsNotExist(err) {
   312  				return nil, fs.ErrorObjectNotFound
   313  			}
   314  			if os.IsPermission(err) {
   315  				return nil, fs.ErrorPermissionDenied
   316  			}
   317  			return nil, err
   318  		}
   319  		// Handle the odd case, that a symlink was specified by name without the link suffix
   320  		if o.fs.opt.TranslateSymlinks && o.mode&os.ModeSymlink != 0 && !o.translatedLink {
   321  			return nil, fs.ErrorObjectNotFound
   322  		}
   323  
   324  	}
   325  	if o.mode.IsDir() {
   326  		return nil, errors.Wrapf(fs.ErrorNotAFile, "%q", remote)
   327  	}
   328  	return o, nil
   329  }
   330  
   331  // NewObject finds the Object at remote.  If it can't be found
   332  // it returns the error ErrorObjectNotFound.
   333  func (f *Fs) NewObject(ctx context.Context, remote string) (fs.Object, error) {
   334  	return f.newObjectWithInfo(remote, "", nil)
   335  }
   336  
   337  // List the objects and directories in dir into entries.  The
   338  // entries can be returned in any order but should be for a
   339  // complete directory.
   340  //
   341  // dir should be "" to list the root, and should not have
   342  // trailing slashes.
   343  //
   344  // This should return ErrDirNotFound if the directory isn't
   345  // found.
   346  func (f *Fs) List(ctx context.Context, dir string) (entries fs.DirEntries, err error) {
   347  
   348  	dir = f.dirNames.Load(dir)
   349  	fsDirPath := f.cleanPath(filepath.Join(f.root, dir))
   350  	remote := f.cleanRemote(dir)
   351  	_, err = os.Stat(fsDirPath)
   352  	if err != nil {
   353  		return nil, fs.ErrorDirNotFound
   354  	}
   355  
   356  	fd, err := os.Open(fsDirPath)
   357  	if err != nil {
   358  		isPerm := os.IsPermission(err)
   359  		err = errors.Wrapf(err, "failed to open directory %q", dir)
   360  		fs.Errorf(dir, "%v", err)
   361  		if isPerm {
   362  			accounting.Stats.Error(fserrors.NoRetryError(err))
   363  			err = nil // ignore error but fail sync
   364  		}
   365  		return nil, err
   366  	}
   367  	defer func() {
   368  		cerr := fd.Close()
   369  		if cerr != nil && err == nil {
   370  			err = errors.Wrapf(cerr, "failed to close directory %q:", dir)
   371  		}
   372  	}()
   373  
   374  	for {
   375  		var fis []os.FileInfo
   376  		if useReadDir {
   377  			// Windows and Plan9 read the directory entries with the stat information in which
   378  			// shouldn't fail because of unreadable entries.
   379  			fis, err = fd.Readdir(1024)
   380  			if err == io.EOF && len(fis) == 0 {
   381  				break
   382  			}
   383  		} else {
   384  			// For other OSes we read the names only (which shouldn't fail) then stat the
   385  			// individual ourselves so we can log errors but not fail the directory read.
   386  			var names []string
   387  			names, err = fd.Readdirnames(1024)
   388  			if err == io.EOF && len(names) == 0 {
   389  				break
   390  			}
   391  			if err == nil {
   392  				for _, name := range names {
   393  					namepath := filepath.Join(fsDirPath, name)
   394  					fi, fierr := os.Lstat(namepath)
   395  					if fierr != nil {
   396  						err = errors.Wrapf(err, "failed to read directory %q", namepath)
   397  						fs.Errorf(dir, "%v", fierr)
   398  						accounting.Stats.Error(fserrors.NoRetryError(fierr)) // fail the sync
   399  						continue
   400  					}
   401  					fis = append(fis, fi)
   402  				}
   403  			}
   404  		}
   405  		if err != nil {
   406  			return nil, errors.Wrap(err, "failed to read directory entry")
   407  		}
   408  
   409  		for _, fi := range fis {
   410  			name := fi.Name()
   411  			mode := fi.Mode()
   412  			newRemote := path.Join(remote, name)
   413  			newPath := filepath.Join(fsDirPath, name)
   414  			// Follow symlinks if required
   415  			if f.opt.FollowSymlinks && (mode&os.ModeSymlink) != 0 {
   416  				fi, err = os.Stat(newPath)
   417  				if os.IsNotExist(err) {
   418  					// Skip bad symlinks
   419  					err = fserrors.NoRetryError(errors.Wrap(err, "symlink"))
   420  					fs.Errorf(newRemote, "Listing error: %v", err)
   421  					accounting.Stats.Error(err)
   422  					continue
   423  				}
   424  				if err != nil {
   425  					return nil, err
   426  				}
   427  				mode = fi.Mode()
   428  			}
   429  			if fi.IsDir() {
   430  				// Ignore directories which are symlinks.  These are junction points under windows which
   431  				// are kind of a souped up symlink. Unix doesn't have directories which are symlinks.
   432  				if (mode&os.ModeSymlink) == 0 && f.dev == readDevice(fi, f.opt.OneFileSystem) {
   433  					d := fs.NewDir(f.dirNames.Save(newRemote, f.cleanRemote(newRemote)), fi.ModTime())
   434  					entries = append(entries, d)
   435  				}
   436  			} else {
   437  				// Check whether this link should be translated
   438  				if f.opt.TranslateSymlinks && fi.Mode()&os.ModeSymlink != 0 {
   439  					newRemote += linkSuffix
   440  				}
   441  				fso, err := f.newObjectWithInfo(newRemote, newPath, fi)
   442  				if err != nil {
   443  					return nil, err
   444  				}
   445  				if fso.Storable() {
   446  					entries = append(entries, fso)
   447  				}
   448  			}
   449  		}
   450  	}
   451  	return entries, nil
   452  }
   453  
   454  // cleanRemote makes string a valid UTF-8 string for remote strings.
   455  //
   456  // Any invalid UTF-8 characters will be replaced with utf8.RuneError
   457  // It also normalises the UTF-8 and converts the slashes if necessary.
   458  func (f *Fs) cleanRemote(name string) string {
   459  	if !utf8.ValidString(name) {
   460  		f.wmu.Lock()
   461  		if _, ok := f.warned[name]; !ok {
   462  			fs.Logf(f, "Replacing invalid UTF-8 characters in %q", name)
   463  			f.warned[name] = struct{}{}
   464  		}
   465  		f.wmu.Unlock()
   466  		name = string([]rune(name))
   467  	}
   468  	name = filepath.ToSlash(name)
   469  	return name
   470  }
   471  
   472  // mapper maps raw to cleaned directory names
   473  type mapper struct {
   474  	mu sync.RWMutex      // mutex to protect the below
   475  	m  map[string]string // map of un-normalised directory names
   476  }
   477  
   478  func newMapper() *mapper {
   479  	return &mapper{
   480  		m: make(map[string]string),
   481  	}
   482  }
   483  
   484  // Lookup a directory name to make a local name (reverses
   485  // cleanDirName)
   486  //
   487  // FIXME this is temporary before we make a proper Directory object
   488  func (m *mapper) Load(in string) string {
   489  	m.mu.RLock()
   490  	out, ok := m.m[in]
   491  	m.mu.RUnlock()
   492  	if ok {
   493  		return out
   494  	}
   495  	return in
   496  }
   497  
   498  // Cleans a directory name recording if it needed to be altered
   499  //
   500  // FIXME this is temporary before we make a proper Directory object
   501  func (m *mapper) Save(in, out string) string {
   502  	if in != out {
   503  		m.mu.Lock()
   504  		m.m[out] = in
   505  		m.mu.Unlock()
   506  	}
   507  	return out
   508  }
   509  
   510  // Put the Object to the local filesystem
   511  func (f *Fs) Put(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) {
   512  	remote := src.Remote()
   513  	// Temporary Object under construction - info filled in by Update()
   514  	o := f.newObject(remote, "")
   515  	err := o.Update(ctx, in, src, options...)
   516  	if err != nil {
   517  		return nil, err
   518  	}
   519  	return o, nil
   520  }
   521  
   522  // PutStream uploads to the remote path with the modTime given of indeterminate size
   523  func (f *Fs) PutStream(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) (fs.Object, error) {
   524  	return f.Put(ctx, in, src, options...)
   525  }
   526  
   527  // Mkdir creates the directory if it doesn't exist
   528  func (f *Fs) Mkdir(ctx context.Context, dir string) error {
   529  	// FIXME: https://github.com/syncthing/syncthing/blob/master/lib/osutil/mkdirall_windows.go
   530  	root := f.cleanPath(filepath.Join(f.root, dir))
   531  	err := os.MkdirAll(root, 0777)
   532  	if err != nil {
   533  		return err
   534  	}
   535  	if dir == "" {
   536  		fi, err := f.lstat(root)
   537  		if err != nil {
   538  			return err
   539  		}
   540  		f.dev = readDevice(fi, f.opt.OneFileSystem)
   541  	}
   542  	return nil
   543  }
   544  
   545  // Rmdir removes the directory
   546  //
   547  // If it isn't empty it will return an error
   548  func (f *Fs) Rmdir(ctx context.Context, dir string) error {
   549  	root := f.cleanPath(filepath.Join(f.root, dir))
   550  	return os.Remove(root)
   551  }
   552  
   553  // Precision of the file system
   554  func (f *Fs) Precision() (precision time.Duration) {
   555  	f.precisionOk.Do(func() {
   556  		f.precision = f.readPrecision()
   557  	})
   558  	return f.precision
   559  }
   560  
   561  // Read the precision
   562  func (f *Fs) readPrecision() (precision time.Duration) {
   563  	// Default precision of 1s
   564  	precision = time.Second
   565  
   566  	// Create temporary file and test it
   567  	fd, err := ioutil.TempFile("", "rclone")
   568  	if err != nil {
   569  		// If failed return 1s
   570  		// fmt.Println("Failed to create temp file", err)
   571  		return time.Second
   572  	}
   573  	path := fd.Name()
   574  	// fmt.Println("Created temp file", path)
   575  	err = fd.Close()
   576  	if err != nil {
   577  		return time.Second
   578  	}
   579  
   580  	// Delete it on return
   581  	defer func() {
   582  		// fmt.Println("Remove temp file")
   583  		_ = os.Remove(path) // ignore error
   584  	}()
   585  
   586  	// Find the minimum duration we can detect
   587  	for duration := time.Duration(1); duration < time.Second; duration *= 10 {
   588  		// Current time with delta
   589  		t := time.Unix(time.Now().Unix(), int64(duration))
   590  		err := os.Chtimes(path, t, t)
   591  		if err != nil {
   592  			// fmt.Println("Failed to Chtimes", err)
   593  			break
   594  		}
   595  
   596  		// Read the actual time back
   597  		fi, err := os.Stat(path)
   598  		if err != nil {
   599  			// fmt.Println("Failed to Stat", err)
   600  			break
   601  		}
   602  
   603  		// If it matches - have found the precision
   604  		// fmt.Println("compare", fi.ModTime(ctx), t)
   605  		if fi.ModTime().Equal(t) {
   606  			// fmt.Println("Precision detected as", duration)
   607  			return duration
   608  		}
   609  	}
   610  	return
   611  }
   612  
   613  // Purge deletes all the files and directories
   614  //
   615  // Optional interface: Only implement this if you have a way of
   616  // deleting all the files quicker than just running Remove() on the
   617  // result of List()
   618  func (f *Fs) Purge(ctx context.Context) error {
   619  	fi, err := f.lstat(f.root)
   620  	if err != nil {
   621  		return err
   622  	}
   623  	if !fi.Mode().IsDir() {
   624  		return errors.Errorf("can't purge non directory: %q", f.root)
   625  	}
   626  	return os.RemoveAll(f.root)
   627  }
   628  
   629  // Move src to this remote using server side move operations.
   630  //
   631  // This is stored with the remote path given
   632  //
   633  // It returns the destination Object and a possible error
   634  //
   635  // Will only be called if src.Fs().Name() == f.Name()
   636  //
   637  // If it isn't possible then return fs.ErrorCantMove
   638  func (f *Fs) Move(ctx context.Context, src fs.Object, remote string) (fs.Object, error) {
   639  	srcObj, ok := src.(*Object)
   640  	if !ok {
   641  		fs.Debugf(src, "Can't move - not same remote type")
   642  		return nil, fs.ErrorCantMove
   643  	}
   644  
   645  	// Temporary Object under construction
   646  	dstObj := f.newObject(remote, "")
   647  
   648  	// Check it is a file if it exists
   649  	err := dstObj.lstat()
   650  	if os.IsNotExist(err) {
   651  		// OK
   652  	} else if err != nil {
   653  		return nil, err
   654  	} else if !dstObj.fs.isRegular(dstObj.mode) {
   655  		// It isn't a file
   656  		return nil, errors.New("can't move file onto non-file")
   657  	}
   658  
   659  	// Create destination
   660  	err = dstObj.mkdirAll()
   661  	if err != nil {
   662  		return nil, err
   663  	}
   664  
   665  	// Do the move
   666  	err = os.Rename(srcObj.path, dstObj.path)
   667  	if os.IsNotExist(err) {
   668  		// race condition, source was deleted in the meantime
   669  		return nil, err
   670  	} else if os.IsPermission(err) {
   671  		// not enough rights to write to dst
   672  		return nil, err
   673  	} else if err != nil {
   674  		// not quite clear, but probably trying to move a file across file system
   675  		// boundaries. Copying might still work.
   676  		fs.Debugf(src, "Can't move: %v: trying copy", err)
   677  		return nil, fs.ErrorCantMove
   678  	}
   679  
   680  	// Update the info
   681  	err = dstObj.lstat()
   682  	if err != nil {
   683  		return nil, err
   684  	}
   685  
   686  	return dstObj, nil
   687  }
   688  
   689  // DirMove moves src, srcRemote to this remote at dstRemote
   690  // using server side move operations.
   691  //
   692  // Will only be called if src.Fs().Name() == f.Name()
   693  //
   694  // If it isn't possible then return fs.ErrorCantDirMove
   695  //
   696  // If destination exists then return fs.ErrorDirExists
   697  func (f *Fs) DirMove(ctx context.Context, src fs.Fs, srcRemote, dstRemote string) error {
   698  	srcFs, ok := src.(*Fs)
   699  	if !ok {
   700  		fs.Debugf(srcFs, "Can't move directory - not same remote type")
   701  		return fs.ErrorCantDirMove
   702  	}
   703  	srcPath := f.cleanPath(filepath.Join(srcFs.root, srcRemote))
   704  	dstPath := f.cleanPath(filepath.Join(f.root, dstRemote))
   705  
   706  	// Check if destination exists
   707  	_, err := os.Lstat(dstPath)
   708  	if !os.IsNotExist(err) {
   709  		return fs.ErrorDirExists
   710  	}
   711  
   712  	// Create parent of destination
   713  	dstParentPath := filepath.Dir(dstPath)
   714  	err = os.MkdirAll(dstParentPath, 0777)
   715  	if err != nil {
   716  		return err
   717  	}
   718  
   719  	// Do the move
   720  	err = os.Rename(srcPath, dstPath)
   721  	if os.IsNotExist(err) {
   722  		// race condition, source was deleted in the meantime
   723  		return err
   724  	} else if os.IsPermission(err) {
   725  		// not enough rights to write to dst
   726  		return err
   727  	} else if err != nil {
   728  		// not quite clear, but probably trying to move directory across file system
   729  		// boundaries. Copying might still work.
   730  		fs.Debugf(src, "Can't move dir: %v: trying copy", err)
   731  		return fs.ErrorCantDirMove
   732  	}
   733  	return nil
   734  }
   735  
   736  // Hashes returns the supported hash sets.
   737  func (f *Fs) Hashes() hash.Set {
   738  	return hash.Supported
   739  }
   740  
   741  // ------------------------------------------------------------
   742  
   743  // Fs returns the parent Fs
   744  func (o *Object) Fs() fs.Info {
   745  	return o.fs
   746  }
   747  
   748  // Return a string version
   749  func (o *Object) String() string {
   750  	if o == nil {
   751  		return "<nil>"
   752  	}
   753  	return o.remote
   754  }
   755  
   756  // Remote returns the remote path
   757  func (o *Object) Remote() string {
   758  	return o.remote
   759  }
   760  
   761  // Hash returns the requested hash of a file as a lowercase hex string
   762  func (o *Object) Hash(ctx context.Context, r hash.Type) (string, error) {
   763  	// Check that the underlying file hasn't changed
   764  	oldtime := o.modTime
   765  	oldsize := o.size
   766  	err := o.lstat()
   767  	if err != nil {
   768  		return "", errors.Wrap(err, "hash: failed to stat")
   769  	}
   770  
   771  	o.fs.objectHashesMu.Lock()
   772  	hashes := o.hashes
   773  	hashValue, hashFound := o.hashes[r]
   774  	o.fs.objectHashesMu.Unlock()
   775  
   776  	if !o.modTime.Equal(oldtime) || oldsize != o.size || hashes == nil || !hashFound {
   777  		var in io.ReadCloser
   778  
   779  		if !o.translatedLink {
   780  			in, err = file.Open(o.path)
   781  		} else {
   782  			in, err = o.openTranslatedLink(0, -1)
   783  		}
   784  		if err != nil {
   785  			return "", errors.Wrap(err, "hash: failed to open")
   786  		}
   787  		hashes, err = hash.StreamTypes(in, hash.NewHashSet(r))
   788  		closeErr := in.Close()
   789  		if err != nil {
   790  			return "", errors.Wrap(err, "hash: failed to read")
   791  		}
   792  		if closeErr != nil {
   793  			return "", errors.Wrap(closeErr, "hash: failed to close")
   794  		}
   795  		hashValue = hashes[r]
   796  		o.fs.objectHashesMu.Lock()
   797  		if o.hashes == nil {
   798  			o.hashes = hashes
   799  		} else {
   800  			o.hashes[r] = hashValue
   801  		}
   802  		o.fs.objectHashesMu.Unlock()
   803  	}
   804  	return hashValue, nil
   805  }
   806  
   807  // Size returns the size of an object in bytes
   808  func (o *Object) Size() int64 {
   809  	return o.size
   810  }
   811  
   812  // ModTime returns the modification time of the object
   813  func (o *Object) ModTime(ctx context.Context) time.Time {
   814  	return o.modTime
   815  }
   816  
   817  // SetModTime sets the modification time of the local fs object
   818  func (o *Object) SetModTime(ctx context.Context, modTime time.Time) error {
   819  	var err error
   820  	if o.translatedLink {
   821  		err = lChtimes(o.path, modTime, modTime)
   822  	} else {
   823  		err = os.Chtimes(o.path, modTime, modTime)
   824  	}
   825  	if err != nil {
   826  		return err
   827  	}
   828  	// Re-read metadata
   829  	return o.lstat()
   830  }
   831  
   832  // Storable returns a boolean showing if this object is storable
   833  func (o *Object) Storable() bool {
   834  	// Check for control characters in the remote name and show non storable
   835  	for _, c := range o.Remote() {
   836  		if c >= 0x00 && c < 0x20 || c == 0x7F {
   837  			fs.Logf(o.fs, "Can't store file with control characters: %q", o.Remote())
   838  			return false
   839  		}
   840  	}
   841  	mode := o.mode
   842  	if mode&os.ModeSymlink != 0 && !o.fs.opt.TranslateSymlinks {
   843  		if !o.fs.opt.SkipSymlinks {
   844  			fs.Logf(o, "Can't follow symlink without -L/--copy-links")
   845  		}
   846  		return false
   847  	} else if mode&(os.ModeNamedPipe|os.ModeSocket|os.ModeDevice) != 0 {
   848  		fs.Logf(o, "Can't transfer non file/directory")
   849  		return false
   850  	} else if mode&os.ModeDir != 0 {
   851  		// fs.Debugf(o, "Skipping directory")
   852  		return false
   853  	}
   854  	return true
   855  }
   856  
   857  // localOpenFile wraps an io.ReadCloser and updates the md5sum of the
   858  // object that is read
   859  type localOpenFile struct {
   860  	o    *Object           // object that is open
   861  	in   io.ReadCloser     // handle we are wrapping
   862  	hash *hash.MultiHasher // currently accumulating hashes
   863  	fd   *os.File          // file object reference
   864  }
   865  
   866  // Read bytes from the object - see io.Reader
   867  func (file *localOpenFile) Read(p []byte) (n int, err error) {
   868  	if !file.o.fs.opt.NoCheckUpdated {
   869  		// Check if file has the same size and modTime
   870  		fi, err := file.fd.Stat()
   871  		if err != nil {
   872  			return 0, errors.Wrap(err, "can't read status of source file while transferring")
   873  		}
   874  		if file.o.size != fi.Size() {
   875  			return 0, errors.Errorf("can't copy - source file is being updated (size changed from %d to %d)", file.o.size, fi.Size())
   876  		}
   877  		if !file.o.modTime.Equal(fi.ModTime()) {
   878  			return 0, errors.Errorf("can't copy - source file is being updated (mod time changed from %v to %v)", file.o.modTime, fi.ModTime())
   879  		}
   880  	}
   881  
   882  	n, err = file.in.Read(p)
   883  	if n > 0 {
   884  		// Hash routines never return an error
   885  		_, _ = file.hash.Write(p[:n])
   886  	}
   887  	return
   888  }
   889  
   890  // Close the object and update the hashes
   891  func (file *localOpenFile) Close() (err error) {
   892  	err = file.in.Close()
   893  	if err == nil {
   894  		if file.hash.Size() == file.o.Size() {
   895  			file.o.fs.objectHashesMu.Lock()
   896  			file.o.hashes = file.hash.Sums()
   897  			file.o.fs.objectHashesMu.Unlock()
   898  		}
   899  	}
   900  	return err
   901  }
   902  
   903  // Returns a ReadCloser() object that contains the contents of a symbolic link
   904  func (o *Object) openTranslatedLink(offset, limit int64) (lrc io.ReadCloser, err error) {
   905  	// Read the link and return the destination  it as the contents of the object
   906  	linkdst, err := os.Readlink(o.path)
   907  	if err != nil {
   908  		return nil, err
   909  	}
   910  	return readers.NewLimitedReadCloser(ioutil.NopCloser(strings.NewReader(linkdst[offset:])), limit), nil
   911  }
   912  
   913  // Open an object for read
   914  func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (in io.ReadCloser, err error) {
   915  	var offset, limit int64 = 0, -1
   916  	hashes := hash.Supported
   917  	for _, option := range options {
   918  		switch x := option.(type) {
   919  		case *fs.SeekOption:
   920  			offset = x.Offset
   921  		case *fs.RangeOption:
   922  			offset, limit = x.Decode(o.size)
   923  		case *fs.HashesOption:
   924  			hashes = x.Hashes
   925  		default:
   926  			if option.Mandatory() {
   927  				fs.Logf(o, "Unsupported mandatory option: %v", option)
   928  			}
   929  		}
   930  	}
   931  
   932  	// Handle a translated link
   933  	if o.translatedLink {
   934  		return o.openTranslatedLink(offset, limit)
   935  	}
   936  
   937  	fd, err := file.Open(o.path)
   938  	if err != nil {
   939  		return
   940  	}
   941  	wrappedFd := readers.NewLimitedReadCloser(fd, limit)
   942  	if offset != 0 {
   943  		// seek the object
   944  		_, err = fd.Seek(offset, io.SeekStart)
   945  		// don't attempt to make checksums
   946  		return wrappedFd, err
   947  	}
   948  	hash, err := hash.NewMultiHasherTypes(hashes)
   949  	if err != nil {
   950  		return nil, err
   951  	}
   952  	// Update the md5sum as we go along
   953  	in = &localOpenFile{
   954  		o:    o,
   955  		in:   wrappedFd,
   956  		hash: hash,
   957  		fd:   fd,
   958  	}
   959  	return in, nil
   960  }
   961  
   962  // mkdirAll makes all the directories needed to store the object
   963  func (o *Object) mkdirAll() error {
   964  	dir := filepath.Dir(o.path)
   965  	return os.MkdirAll(dir, 0777)
   966  }
   967  
   968  type nopWriterCloser struct {
   969  	*bytes.Buffer
   970  }
   971  
   972  func (nwc nopWriterCloser) Close() error {
   973  	// noop
   974  	return nil
   975  }
   976  
   977  // Update the object from in with modTime and size
   978  func (o *Object) Update(ctx context.Context, in io.Reader, src fs.ObjectInfo, options ...fs.OpenOption) error {
   979  	var out io.WriteCloser
   980  
   981  	hashes := hash.Supported
   982  	for _, option := range options {
   983  		switch x := option.(type) {
   984  		case *fs.HashesOption:
   985  			hashes = x.Hashes
   986  		}
   987  	}
   988  
   989  	err := o.mkdirAll()
   990  	if err != nil {
   991  		return err
   992  	}
   993  
   994  	var symlinkData bytes.Buffer
   995  	// If the object is a regular file, create it.
   996  	// If it is a translated link, just read in the contents, and
   997  	// then create a symlink
   998  	if !o.translatedLink {
   999  		f, err := file.OpenFile(o.path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
  1000  		if err != nil {
  1001  			return err
  1002  		}
  1003  		// Pre-allocate the file for performance reasons
  1004  		err = preAllocate(src.Size(), f)
  1005  		if err != nil {
  1006  			fs.Debugf(o, "Failed to pre-allocate: %v", err)
  1007  		}
  1008  		out = f
  1009  	} else {
  1010  		out = nopWriterCloser{&symlinkData}
  1011  	}
  1012  
  1013  	// Calculate the hash of the object we are reading as we go along
  1014  	hash, err := hash.NewMultiHasherTypes(hashes)
  1015  	if err != nil {
  1016  		return err
  1017  	}
  1018  	in = io.TeeReader(in, hash)
  1019  
  1020  	_, err = io.Copy(out, in)
  1021  	closeErr := out.Close()
  1022  	if err == nil {
  1023  		err = closeErr
  1024  	}
  1025  
  1026  	if o.translatedLink {
  1027  		if err == nil {
  1028  			// Remove any current symlink or file, if one exists
  1029  			if _, err := os.Lstat(o.path); err == nil {
  1030  				if removeErr := os.Remove(o.path); removeErr != nil {
  1031  					fs.Errorf(o, "Failed to remove previous file: %v", removeErr)
  1032  					return removeErr
  1033  				}
  1034  			}
  1035  			// Use the contents for the copied object to create a symlink
  1036  			err = os.Symlink(symlinkData.String(), o.path)
  1037  		}
  1038  
  1039  		// only continue if symlink creation succeeded
  1040  		if err != nil {
  1041  			return err
  1042  		}
  1043  	}
  1044  
  1045  	if err != nil {
  1046  		fs.Logf(o, "Removing partially written file on error: %v", err)
  1047  		if removeErr := os.Remove(o.path); removeErr != nil {
  1048  			fs.Errorf(o, "Failed to remove partially written file: %v", removeErr)
  1049  		}
  1050  		return err
  1051  	}
  1052  
  1053  	// All successful so update the hashes
  1054  	o.fs.objectHashesMu.Lock()
  1055  	o.hashes = hash.Sums()
  1056  	o.fs.objectHashesMu.Unlock()
  1057  
  1058  	// Set the mtime
  1059  	err = o.SetModTime(ctx, src.ModTime(ctx))
  1060  	if err != nil {
  1061  		return err
  1062  	}
  1063  
  1064  	// ReRead info now that we have finished
  1065  	return o.lstat()
  1066  }
  1067  
  1068  // OpenWriterAt opens with a handle for random access writes
  1069  //
  1070  // Pass in the remote desired and the size if known.
  1071  //
  1072  // It truncates any existing object
  1073  func (f *Fs) OpenWriterAt(ctx context.Context, remote string, size int64) (fs.WriterAtCloser, error) {
  1074  	// Temporary Object under construction
  1075  	o := f.newObject(remote, "")
  1076  
  1077  	err := o.mkdirAll()
  1078  	if err != nil {
  1079  		return nil, err
  1080  	}
  1081  
  1082  	if o.translatedLink {
  1083  		return nil, errors.New("can't open a symlink for random writing")
  1084  	}
  1085  
  1086  	out, err := file.OpenFile(o.path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
  1087  	if err != nil {
  1088  		return nil, err
  1089  	}
  1090  	// Pre-allocate the file for performance reasons
  1091  	err = preAllocate(size, out)
  1092  	if err != nil {
  1093  		fs.Debugf(o, "Failed to pre-allocate: %v", err)
  1094  	}
  1095  	return out, nil
  1096  }
  1097  
  1098  // setMetadata sets the file info from the os.FileInfo passed in
  1099  func (o *Object) setMetadata(info os.FileInfo) {
  1100  	// Don't overwrite the info if we don't need to
  1101  	// this avoids upsetting the race detector
  1102  	if o.size != info.Size() {
  1103  		o.size = info.Size()
  1104  	}
  1105  	if !o.modTime.Equal(info.ModTime()) {
  1106  		o.modTime = info.ModTime()
  1107  	}
  1108  	if o.mode != info.Mode() {
  1109  		o.mode = info.Mode()
  1110  	}
  1111  }
  1112  
  1113  // Stat a Object into info
  1114  func (o *Object) lstat() error {
  1115  	info, err := o.fs.lstat(o.path)
  1116  	if err == nil {
  1117  		o.setMetadata(info)
  1118  	}
  1119  	return err
  1120  }
  1121  
  1122  // Remove an object
  1123  func (o *Object) Remove(ctx context.Context) error {
  1124  	return remove(o.path)
  1125  }
  1126  
  1127  // cleanPathFragment cleans an OS path fragment which is part of a
  1128  // bigger path and not necessarily absolute
  1129  func cleanPathFragment(s string) string {
  1130  	if s == "" {
  1131  		return s
  1132  	}
  1133  	s = filepath.Clean(s)
  1134  	if runtime.GOOS == "windows" {
  1135  		s = strings.Replace(s, `/`, `\`, -1)
  1136  	}
  1137  	return s
  1138  }
  1139  
  1140  // cleanPath cleans and makes absolute the path passed in and returns
  1141  // an OS path.
  1142  //
  1143  // The input might be in OS form or rclone form or a mixture, but the
  1144  // output is in OS form.
  1145  //
  1146  // On windows it makes the path UNC also and replaces any characters
  1147  // Windows can't deal with with their replacements.
  1148  func (f *Fs) cleanPath(s string) string {
  1149  	s = cleanPathFragment(s)
  1150  	if runtime.GOOS == "windows" {
  1151  		if !filepath.IsAbs(s) && !strings.HasPrefix(s, "\\") {
  1152  			s2, err := filepath.Abs(s)
  1153  			if err == nil {
  1154  				s = s2
  1155  			}
  1156  		}
  1157  		if !f.opt.NoUNC {
  1158  			// Convert to UNC
  1159  			s = uncPath(s)
  1160  		}
  1161  		s = cleanWindowsName(f, s)
  1162  	} else {
  1163  		if !filepath.IsAbs(s) {
  1164  			s2, err := filepath.Abs(s)
  1165  			if err == nil {
  1166  				s = s2
  1167  			}
  1168  		}
  1169  	}
  1170  	return s
  1171  }
  1172  
  1173  // Pattern to match a windows absolute path: "c:\" and similar
  1174  var isAbsWinDrive = regexp.MustCompile(`^[a-zA-Z]\:\\`)
  1175  
  1176  // uncPath converts an absolute Windows path
  1177  // to a UNC long path.
  1178  func uncPath(s string) string {
  1179  	// UNC can NOT use "/", so convert all to "\"
  1180  	s = strings.Replace(s, `/`, `\`, -1)
  1181  
  1182  	// If prefix is "\\", we already have a UNC path or server.
  1183  	if strings.HasPrefix(s, `\\`) {
  1184  		// If already long path, just keep it
  1185  		if strings.HasPrefix(s, `\\?\`) {
  1186  			return s
  1187  		}
  1188  
  1189  		// Trim "\\" from path and add UNC prefix.
  1190  		return `\\?\UNC\` + strings.TrimPrefix(s, `\\`)
  1191  	}
  1192  	if isAbsWinDrive.MatchString(s) {
  1193  		return `\\?\` + s
  1194  	}
  1195  	return s
  1196  }
  1197  
  1198  // cleanWindowsName will clean invalid Windows characters replacing them with _
  1199  func cleanWindowsName(f *Fs, name string) string {
  1200  	original := name
  1201  	var name2 string
  1202  	if strings.HasPrefix(name, `\\?\`) {
  1203  		name2 = `\\?\`
  1204  		name = strings.TrimPrefix(name, `\\?\`)
  1205  	}
  1206  	if strings.HasPrefix(name, `//?/`) {
  1207  		name2 = `//?/`
  1208  		name = strings.TrimPrefix(name, `//?/`)
  1209  	}
  1210  	// Colon is allowed as part of a drive name X:\
  1211  	colonAt := strings.Index(name, ":")
  1212  	if colonAt > 0 && colonAt < 3 && len(name) > colonAt+1 {
  1213  		// Copy to name2, which is unfiltered
  1214  		name2 += name[0 : colonAt+1]
  1215  		name = name[colonAt+1:]
  1216  	}
  1217  
  1218  	name2 += strings.Map(func(r rune) rune {
  1219  		switch r {
  1220  		case '<', '>', '"', '|', '?', '*', ':':
  1221  			return '_'
  1222  		}
  1223  		return r
  1224  	}, name)
  1225  
  1226  	if name2 != original && f != nil {
  1227  		f.wmu.Lock()
  1228  		if _, ok := f.warned[name]; !ok {
  1229  			fs.Logf(f, "Replacing invalid characters in %q to %q", name, name2)
  1230  			f.warned[name] = struct{}{}
  1231  		}
  1232  		f.wmu.Unlock()
  1233  	}
  1234  	return name2
  1235  }
  1236  
  1237  // Check the interfaces are satisfied
  1238  var (
  1239  	_ fs.Fs             = &Fs{}
  1240  	_ fs.Purger         = &Fs{}
  1241  	_ fs.PutStreamer    = &Fs{}
  1242  	_ fs.Mover          = &Fs{}
  1243  	_ fs.DirMover       = &Fs{}
  1244  	_ fs.OpenWriterAter = &Fs{}
  1245  	_ fs.Object         = &Object{}
  1246  )