github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/vfs/dir.go (about)

     1  package vfs
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"path"
     8  	"sort"
     9  	"strings"
    10  	"sync"
    11  	"sync/atomic"
    12  	"time"
    13  
    14  	"github.com/rclone/rclone/fs"
    15  	"github.com/rclone/rclone/fs/dirtree"
    16  	"github.com/rclone/rclone/fs/list"
    17  	"github.com/rclone/rclone/fs/log"
    18  	"github.com/rclone/rclone/fs/operations"
    19  	"github.com/rclone/rclone/fs/walk"
    20  	"github.com/rclone/rclone/vfs/vfscommon"
    21  	"golang.org/x/text/unicode/norm"
    22  )
    23  
    24  // Dir represents a directory entry
    25  type Dir struct {
    26  	vfs          *VFS        // read only
    27  	inode        uint64      // read only: inode number
    28  	f            fs.Fs       // read only
    29  	cleanupTimer *time.Timer // read only: timer to call cacheCleanup
    30  
    31  	mu      sync.RWMutex // protects the following
    32  	parent  *Dir         // parent, nil for root
    33  	path    string
    34  	entry   fs.Directory
    35  	read    time.Time         // time directory entry last read
    36  	items   map[string]Node   // directory entries - can be empty but not nil
    37  	virtual map[string]vState // virtual directory entries - may be nil
    38  	sys     atomic.Value      // user defined info to be attached here
    39  
    40  	modTimeMu sync.Mutex // protects the following
    41  	modTime   time.Time
    42  
    43  	_hasVirtual atomic.Bool // shows if the directory has virtual entries
    44  }
    45  
    46  //go:generate stringer -type=vState
    47  
    48  // vState describes the state of the virtual directory entries
    49  type vState byte
    50  
    51  const (
    52  	vOK      vState = iota // Not virtual
    53  	vAddFile               // added file
    54  	vAddDir                // added directory
    55  	vDel                   // removed file or directory
    56  )
    57  
    58  func newDir(vfs *VFS, f fs.Fs, parent *Dir, fsDir fs.Directory) *Dir {
    59  	d := &Dir{
    60  		vfs:     vfs,
    61  		f:       f,
    62  		parent:  parent,
    63  		entry:   fsDir,
    64  		path:    fsDir.Remote(),
    65  		modTime: fsDir.ModTime(context.TODO()),
    66  		inode:   newInode(),
    67  		items:   make(map[string]Node),
    68  	}
    69  	d.cleanupTimer = time.AfterFunc(vfs.Opt.DirCacheTime*2, d.cacheCleanup)
    70  	d.setHasVirtual(false)
    71  	return d
    72  }
    73  
    74  func (d *Dir) cacheCleanup() {
    75  	defer func() {
    76  		// We should never panic here
    77  		_ = recover()
    78  	}()
    79  
    80  	when := time.Now()
    81  
    82  	d.mu.Lock()
    83  	_, stale := d._age(when)
    84  	d.mu.Unlock()
    85  
    86  	if stale {
    87  		d.ForgetAll()
    88  	}
    89  }
    90  
    91  // String converts it to printable
    92  func (d *Dir) String() string {
    93  	if d == nil {
    94  		return "<nil *Dir>"
    95  	}
    96  	d.mu.RLock()
    97  	defer d.mu.RUnlock()
    98  	return d.path + "/"
    99  }
   100  
   101  // Dumps the directory tree to the string builder with the given indent
   102  //
   103  //lint:ignore U1000 false positive when running staticcheck,
   104  //nolint:unused // Don't include unused when running golangci-lint
   105  func (d *Dir) dumpIndent(out *strings.Builder, indent string) {
   106  	if d == nil {
   107  		fmt.Fprintf(out, "%s<nil *Dir>\n", indent)
   108  		return
   109  	}
   110  	d.mu.RLock()
   111  	defer d.mu.RUnlock()
   112  	fmt.Fprintf(out, "%sPath: %s\n", indent, d.path)
   113  	fmt.Fprintf(out, "%sEntry: %v\n", indent, d.entry)
   114  	fmt.Fprintf(out, "%sRead: %v\n", indent, d.read)
   115  	fmt.Fprintf(out, "%s- items %d\n", indent, len(d.items))
   116  	// Sort?
   117  	for leaf, node := range d.items {
   118  		switch x := node.(type) {
   119  		case *Dir:
   120  			fmt.Fprintf(out, "%s  %s/ - %v\n", indent, leaf, x)
   121  			// check the parent is correct
   122  			if x.parent != d {
   123  				fmt.Fprintf(out, "%s  PARENT POINTER WRONG\n", indent)
   124  			}
   125  			x.dumpIndent(out, indent+"\t")
   126  		case *File:
   127  			fmt.Fprintf(out, "%s  %s - %v\n", indent, leaf, x)
   128  		default:
   129  			panic("bad dir entry")
   130  		}
   131  	}
   132  	fmt.Fprintf(out, "%s- virtual %d\n", indent, len(d.virtual))
   133  	for leaf, state := range d.virtual {
   134  		fmt.Fprintf(out, "%s  %s - %v\n", indent, leaf, state)
   135  	}
   136  }
   137  
   138  // Dumps a nicely formatted directory tree to a string
   139  //
   140  //lint:ignore U1000 false positive when running staticcheck,
   141  //nolint:unused // Don't include unused when running golangci-lint
   142  func (d *Dir) dump() string {
   143  	var out strings.Builder
   144  	d.dumpIndent(&out, "")
   145  	return out.String()
   146  }
   147  
   148  // IsFile returns false for Dir - satisfies Node interface
   149  func (d *Dir) IsFile() bool {
   150  	return false
   151  }
   152  
   153  // IsDir returns true for Dir - satisfies Node interface
   154  func (d *Dir) IsDir() bool {
   155  	return true
   156  }
   157  
   158  // Mode bits of the directory - satisfies Node interface
   159  func (d *Dir) Mode() (mode os.FileMode) {
   160  	return d.vfs.Opt.DirPerms
   161  }
   162  
   163  // Name (base) of the directory - satisfies Node interface
   164  func (d *Dir) Name() (name string) {
   165  	d.mu.RLock()
   166  	name = path.Base(d.path)
   167  	d.mu.RUnlock()
   168  	if name == "." {
   169  		name = "/"
   170  	}
   171  	return name
   172  }
   173  
   174  // Path of the directory - satisfies Node interface
   175  func (d *Dir) Path() (name string) {
   176  	d.mu.RLock()
   177  	defer d.mu.RUnlock()
   178  	return d.path
   179  }
   180  
   181  // Sys returns underlying data source (can be nil) - satisfies Node interface
   182  func (d *Dir) Sys() interface{} {
   183  	return d.sys.Load()
   184  }
   185  
   186  // SetSys sets the underlying data source (can be nil) - satisfies Node interface
   187  func (d *Dir) SetSys(x interface{}) {
   188  	d.sys.Store(x)
   189  }
   190  
   191  // Inode returns the inode number - satisfies Node interface
   192  func (d *Dir) Inode() uint64 {
   193  	return d.inode
   194  }
   195  
   196  // Node returns the Node associated with this - satisfies Noder interface
   197  func (d *Dir) Node() Node {
   198  	return d
   199  }
   200  
   201  // hasVirtual returns whether the directory has virtual entries
   202  func (d *Dir) hasVirtual() bool {
   203  	return d._hasVirtual.Load()
   204  }
   205  
   206  // setHasVirtual sets the hasVirtual flag for the directory
   207  func (d *Dir) setHasVirtual(hasVirtual bool) {
   208  	d._hasVirtual.Store(hasVirtual)
   209  }
   210  
   211  // ForgetAll forgets directory entries for this directory and any children.
   212  //
   213  // It does not invalidate or clear the cache of the parent directory.
   214  //
   215  // It returns true if the directory or any of its children had virtual entries
   216  // so could not be forgotten. Children which didn't have virtual entries and
   217  // children with virtual entries will be forgotten even if true is returned.
   218  func (d *Dir) ForgetAll() (hasVirtual bool) {
   219  	d.mu.RLock()
   220  
   221  	fs.Debugf(d.path, "forgetting directory cache")
   222  	for _, node := range d.items {
   223  		if dir, ok := node.(*Dir); ok {
   224  			if dir.ForgetAll() {
   225  				d.setHasVirtual(true)
   226  			}
   227  		}
   228  	}
   229  
   230  	d.mu.RUnlock()
   231  
   232  	d.mu.Lock()
   233  	defer d.mu.Unlock()
   234  
   235  	// Purge any unnecessary virtual entries
   236  	d._purgeVirtual()
   237  
   238  	d.read = time.Time{}
   239  
   240  	// Check if this dir has virtual entries
   241  	if len(d.virtual) != 0 {
   242  		d.setHasVirtual(true)
   243  	}
   244  
   245  	// Don't clear directory entries if there are virtual entries in this
   246  	// directory or any children
   247  	if !d.hasVirtual() {
   248  		d.items = make(map[string]Node)
   249  		d.cleanupTimer.Stop()
   250  	}
   251  
   252  	return d.hasVirtual()
   253  }
   254  
   255  // forgetDirPath clears the cache for itself and all subdirectories if
   256  // they match the given path. The path is specified relative from the
   257  // directory it is called from.
   258  //
   259  // It does not invalidate or clear the cache of the parent directory.
   260  func (d *Dir) forgetDirPath(relativePath string) {
   261  	dir := d.cachedDir(relativePath)
   262  	if dir == nil {
   263  		return
   264  	}
   265  	dir.ForgetAll()
   266  }
   267  
   268  // invalidateDir invalidates the directory cache for absPath relative to the root
   269  func (d *Dir) invalidateDir(absPath string) {
   270  	node := d.vfs.root.cachedNode(absPath)
   271  	if dir, ok := node.(*Dir); ok {
   272  		dir.mu.Lock()
   273  		if !dir.read.IsZero() {
   274  			fs.Debugf(dir.path, "invalidating directory cache")
   275  			dir.read = time.Time{}
   276  		}
   277  		dir.mu.Unlock()
   278  	}
   279  }
   280  
   281  // changeNotify invalidates the directory cache for the relativePath
   282  // passed in.
   283  //
   284  // if entryType is a directory it invalidates the parent of the directory too.
   285  func (d *Dir) changeNotify(relativePath string, entryType fs.EntryType) {
   286  	defer log.Trace(d.path, "relativePath=%q, type=%v", relativePath, entryType)("")
   287  	d.mu.RLock()
   288  	absPath := path.Join(d.path, relativePath)
   289  	d.mu.RUnlock()
   290  	d.invalidateDir(vfscommon.FindParent(absPath))
   291  	if entryType == fs.EntryDirectory {
   292  		d.invalidateDir(absPath)
   293  	}
   294  }
   295  
   296  // ForgetPath clears the cache for itself and all subdirectories if
   297  // they match the given path. The path is specified relative from the
   298  // directory it is called from. The cache of the parent directory is
   299  // marked as stale, but not cleared otherwise.
   300  // It is not possible to traverse the directory tree upwards, i.e.
   301  // you cannot clear the cache for the Dir's ancestors or siblings.
   302  func (d *Dir) ForgetPath(relativePath string, entryType fs.EntryType) {
   303  	defer log.Trace(d.path, "relativePath=%q, type=%v", relativePath, entryType)("")
   304  	d.mu.RLock()
   305  	absPath := path.Join(d.path, relativePath)
   306  	d.mu.RUnlock()
   307  	if absPath != "" {
   308  		d.invalidateDir(vfscommon.FindParent(absPath))
   309  	}
   310  	if entryType == fs.EntryDirectory {
   311  		d.forgetDirPath(relativePath)
   312  	}
   313  }
   314  
   315  // walk runs a function on all cached directories. It will be called
   316  // on a directory's children first.
   317  //
   318  // The mutex will be held for the directory when fun is called
   319  func (d *Dir) walk(fun func(*Dir)) {
   320  	d.mu.Lock()
   321  	defer d.mu.Unlock()
   322  	for _, node := range d.items {
   323  		if dir, ok := node.(*Dir); ok {
   324  			dir.walk(fun)
   325  		}
   326  	}
   327  
   328  	fun(d)
   329  }
   330  
   331  // countActiveWriters returns the number of writers active in this
   332  // directory and any subdirectories.
   333  func (d *Dir) countActiveWriters() (writers int) {
   334  	d.walk(func(d *Dir) {
   335  		// NB d.mu is held by walk() here
   336  		fs.Debugf(d.path, "Looking for writers")
   337  		for leaf, item := range d.items {
   338  			fs.Debugf(leaf, "reading active writers")
   339  			if file, ok := item.(*File); ok {
   340  				n := file.activeWriters()
   341  				if n != 0 {
   342  					fs.Debugf(file, "active writers %d", n)
   343  				}
   344  				writers += n
   345  			}
   346  		}
   347  	})
   348  	return writers
   349  }
   350  
   351  // age returns the duration since the last time the directory contents
   352  // was read and the content is considered stale. age will be 0 and
   353  // stale true if the last read time is empty.
   354  // age must be called with d.mu held.
   355  func (d *Dir) _age(when time.Time) (age time.Duration, stale bool) {
   356  	if d.read.IsZero() {
   357  		return age, true
   358  	}
   359  	age = when.Sub(d.read)
   360  	stale = age > d.vfs.Opt.DirCacheTime
   361  	return
   362  }
   363  
   364  // renameTree renames the directories under this directory
   365  //
   366  // path should be the desired path
   367  func (d *Dir) renameTree(dirPath string) {
   368  	d.mu.Lock()
   369  	defer d.mu.Unlock()
   370  
   371  	// Make sure the path is correct for each node
   372  	if d.path != dirPath {
   373  		fs.Debugf(d.path, "Renaming to %q", dirPath)
   374  		d.path = dirPath
   375  		d.entry = fs.NewDirCopy(context.TODO(), d.entry).SetRemote(dirPath)
   376  	}
   377  
   378  	// Do the same to any child directories and files
   379  	for leaf, node := range d.items {
   380  		switch x := node.(type) {
   381  		case *Dir:
   382  			x.renameTree(path.Join(dirPath, leaf))
   383  		case *File:
   384  			x.renameDir(dirPath)
   385  		default:
   386  			panic("bad dir entry")
   387  		}
   388  	}
   389  }
   390  
   391  // rename should be called after the directory is renamed
   392  //
   393  // Reset the directory to new state, discarding all the objects and
   394  // reading everything again
   395  func (d *Dir) rename(newParent *Dir, fsDir fs.Directory) {
   396  	d.ForgetAll()
   397  
   398  	d.modTimeMu.Lock()
   399  	d.modTime = fsDir.ModTime(context.TODO())
   400  	d.modTimeMu.Unlock()
   401  	d.mu.Lock()
   402  	oldPath := d.path
   403  	d.parent = newParent
   404  	d.entry = fsDir
   405  	d.path = fsDir.Remote()
   406  	newPath := d.path
   407  	d.read = time.Time{}
   408  	d.mu.Unlock()
   409  
   410  	// Rename any remaining items in the tree that we couldn't forget
   411  	d.renameTree(d.path)
   412  
   413  	// Rename in the cache
   414  	if d.vfs.cache != nil && d.vfs.cache.DirExists(oldPath) {
   415  		if err := d.vfs.cache.DirRename(oldPath, newPath); err != nil {
   416  			fs.Infof(d, "Dir.Rename failed in Cache: %v", err)
   417  		}
   418  	}
   419  }
   420  
   421  // addObject adds a new object or directory to the directory
   422  //
   423  // The name passed in is marked as virtual as it hasn't been read from a remote
   424  // directory listing.
   425  //
   426  // note that we add new objects rather than updating old ones
   427  func (d *Dir) addObject(node Node) {
   428  	d.mu.Lock()
   429  	leaf := node.Name()
   430  	d.items[leaf] = node
   431  	if d.virtual == nil {
   432  		d.virtual = make(map[string]vState)
   433  	}
   434  	vAdd := vAddFile
   435  	if node.IsDir() {
   436  		vAdd = vAddDir
   437  	}
   438  	d.virtual[leaf] = vAdd
   439  	d.setHasVirtual(true)
   440  	fs.Debugf(d.path, "Added virtual directory entry %v: %q", vAdd, leaf)
   441  	d.mu.Unlock()
   442  }
   443  
   444  // AddVirtual adds a virtual object of name and size to the directory
   445  //
   446  // This will be replaced with a real object when it is read back from the
   447  // remote.
   448  //
   449  // This is used to add directory entries while things are uploading
   450  func (d *Dir) AddVirtual(leaf string, size int64, isDir bool) {
   451  	var node Node
   452  	d.mu.RLock()
   453  	dPath := d.path
   454  	_, found := d.items[leaf]
   455  	d.mu.RUnlock()
   456  	if found {
   457  		// Don't overwrite existing objects
   458  		return
   459  	}
   460  	if isDir {
   461  		remote := path.Join(dPath, leaf)
   462  		entry := fs.NewDir(remote, time.Now())
   463  		node = newDir(d.vfs, d.f, d, entry)
   464  	} else {
   465  		f := newFile(d, dPath, nil, leaf)
   466  		f.setSize(size)
   467  		node = f
   468  	}
   469  	d.addObject(node)
   470  }
   471  
   472  // delObject removes an object from the directory
   473  //
   474  // The name passed in is marked as virtual as the delete it hasn't been read
   475  // from a remote directory listing.
   476  func (d *Dir) delObject(leaf string) {
   477  	d.mu.Lock()
   478  	delete(d.items, leaf)
   479  	if d.virtual == nil {
   480  		d.virtual = make(map[string]vState)
   481  	}
   482  	d.virtual[leaf] = vDel
   483  	d.setHasVirtual(true)
   484  	fs.Debugf(d.path, "Added virtual directory entry %v: %q", vDel, leaf)
   485  	d.mu.Unlock()
   486  }
   487  
   488  // DelVirtual removes an object from the directory listing
   489  //
   490  // It marks it as removed until it has confirmed the object is missing when the
   491  // directory entries are re-read in.
   492  //
   493  // This is used to remove directory entries after things have been deleted or
   494  // renamed but before we've had confirmation from the backend.
   495  func (d *Dir) DelVirtual(leaf string) {
   496  	d.delObject(leaf)
   497  }
   498  
   499  // read the directory and sets d.items - must be called with the lock held
   500  func (d *Dir) _readDir() error {
   501  	when := time.Now()
   502  	if age, stale := d._age(when); stale {
   503  		if age != 0 {
   504  			fs.Debugf(d.path, "Re-reading directory (%v old)", age)
   505  		}
   506  	} else {
   507  		return nil
   508  	}
   509  	entries, err := list.DirSorted(context.TODO(), d.f, false, d.path)
   510  	if err == fs.ErrorDirNotFound {
   511  		// We treat directory not found as empty because we
   512  		// create directories on the fly
   513  	} else if err != nil {
   514  		return err
   515  	}
   516  
   517  	if d.vfs.Opt.BlockNormDupes { // do this only if requested, as it will have a performance hit
   518  		ci := fs.GetConfig(context.TODO())
   519  
   520  		// sort entries such that NFD comes before NFC of same name
   521  		sort.Slice(entries, func(i, j int) bool {
   522  			if entries[i] != entries[j] && fs.DirEntryType(entries[i]) == fs.DirEntryType(entries[j]) && norm.NFC.String(entries[i].Remote()) == norm.NFC.String(entries[j].Remote()) {
   523  				if norm.NFD.IsNormalString(entries[i].Remote()) && !norm.NFD.IsNormalString(entries[j].Remote()) {
   524  					return true
   525  				}
   526  			}
   527  			return entries.Less(i, j)
   528  		})
   529  
   530  		// detect dupes, remove them from the list and log an error
   531  		normalizedNames := make(map[string]struct{}, entries.Len())
   532  		filteredEntries := make(fs.DirEntries, 0)
   533  		for _, e := range entries {
   534  			normName := fmt.Sprintf("%s-%T", operations.ToNormal(e.Remote(), !ci.NoUnicodeNormalization, (ci.IgnoreCaseSync || d.vfs.Opt.CaseInsensitive)), e) // include type to track objects and dirs separately
   535  			_, found := normalizedNames[normName]
   536  			if found {
   537  				fs.Errorf(e.Remote(), "duplicate normalized names detected - skipping")
   538  				continue
   539  			}
   540  			normalizedNames[normName] = struct{}{}
   541  			filteredEntries = append(filteredEntries, e)
   542  		}
   543  		entries = filteredEntries
   544  	}
   545  
   546  	err = d._readDirFromEntries(entries, nil, time.Time{})
   547  	if err != nil {
   548  		return err
   549  	}
   550  
   551  	d.read = when
   552  	d.cleanupTimer.Reset(d.vfs.Opt.DirCacheTime * 2)
   553  
   554  	return nil
   555  }
   556  
   557  // update d.items for each dir in the DirTree below this one and
   558  // set the last read time - must be called with the lock held
   559  func (d *Dir) _readDirFromDirTree(dirTree dirtree.DirTree, when time.Time) error {
   560  	return d._readDirFromEntries(dirTree[d.path], dirTree, when)
   561  }
   562  
   563  // Remove the virtual directory entry leaf
   564  func (d *Dir) _deleteVirtual(name string) {
   565  	virtualState, ok := d.virtual[name]
   566  	if !ok {
   567  		return
   568  	}
   569  	delete(d.virtual, name)
   570  	if len(d.virtual) == 0 {
   571  		d.virtual = nil
   572  		d.setHasVirtual(false)
   573  	}
   574  	fs.Debugf(d.path, "Removed virtual directory entry %v: %q", virtualState, name)
   575  }
   576  
   577  // Purge virtual entries assuming the directory has just been re-read
   578  //
   579  // Remove all the entries except:
   580  //
   581  // 1) vDirAdd on remotes which can't have empty directories. These will remain
   582  // virtual as long as the directory is empty. When the directory becomes real
   583  // (ie files are added) the virtual directory will be removed. This means that
   584  // directories will disappear when the last file is deleted which is probably
   585  // OK.
   586  //
   587  // 2) vFileAdd that are being written or uploaded
   588  func (d *Dir) _purgeVirtual() {
   589  	canHaveEmptyDirectories := d.f.Features().CanHaveEmptyDirectories
   590  	for name, virtualState := range d.virtual {
   591  		switch virtualState {
   592  		case vAddDir:
   593  			if canHaveEmptyDirectories {
   594  				// if remote can have empty directories then a
   595  				// new dir will be read in the listing
   596  				d._deleteVirtual(name)
   597  				//} else {
   598  				// leave the empty directory marker
   599  			}
   600  		case vAddFile:
   601  			// Delete all virtual file adds that have finished uploading
   602  			node, ok := d.items[name]
   603  			if !ok {
   604  				// if the object has disappeared somehow then remove the virtual
   605  				d._deleteVirtual(name)
   606  				continue
   607  			}
   608  			f, ok := node.(*File)
   609  			if !ok {
   610  				// if the object isn't a file then remove the virtual as it is wrong
   611  				d._deleteVirtual(name)
   612  				continue
   613  			}
   614  			if f.writingInProgress() {
   615  				// if writing in progress then leave virtual
   616  				continue
   617  			}
   618  			if d.vfs.Opt.CacheMode >= vfscommon.CacheModeMinimal && d.vfs.cache.InUse(f.Path()) {
   619  				// if object in use or dirty then leave virtual
   620  				continue
   621  			}
   622  			d._deleteVirtual(name)
   623  		default:
   624  			d._deleteVirtual(name)
   625  		}
   626  	}
   627  }
   628  
   629  // Manage the virtuals in a listing
   630  //
   631  // This keeps a record of the names listed in this directory so far
   632  type manageVirtuals map[string]struct{}
   633  
   634  // Create a new manageVirtuals and purge the d.virtuals of any entries which can
   635  // be removed.
   636  //
   637  // must be called with the Dir lock held
   638  func (d *Dir) _newManageVirtuals() manageVirtuals {
   639  	tv := make(manageVirtuals)
   640  	d._purgeVirtual()
   641  	return tv
   642  }
   643  
   644  // This should be called for every entry added to the directory
   645  //
   646  // It returns true if this entry should be skipped.
   647  //
   648  // must be called with the Dir lock held
   649  func (mv manageVirtuals) add(d *Dir, name string) bool {
   650  	// Keep a record of all names listed
   651  	mv[name] = struct{}{}
   652  	// Remove virtuals if possible
   653  	switch d.virtual[name] {
   654  	case vAddFile, vAddDir:
   655  		// item was added to the dir but since it is found in a
   656  		// listing is no longer virtual
   657  		d._deleteVirtual(name)
   658  	case vDel:
   659  		// item is deleted from the dir so skip it
   660  		return true
   661  	case vOK:
   662  	}
   663  	return false
   664  }
   665  
   666  // This should be called after the directory entry is read to update d.items
   667  // with virtual entries
   668  //
   669  // must be called with the Dir lock held
   670  func (mv manageVirtuals) end(d *Dir) {
   671  	// delete unused d.items
   672  	for name := range d.items {
   673  		if _, ok := mv[name]; !ok {
   674  			// name was previously in the directory but wasn't found
   675  			// in the current listing
   676  			switch d.virtual[name] {
   677  			case vAddFile, vAddDir:
   678  				// virtually added so leave virtual item
   679  			default:
   680  				// otherwise delete it
   681  				delete(d.items, name)
   682  			}
   683  		}
   684  	}
   685  	// delete unused d.virtual~s
   686  	for name, virtualState := range d.virtual {
   687  		if _, ok := mv[name]; !ok {
   688  			// name exists as a virtual but isn't in the current
   689  			// listing so if it is a virtual delete we can remove it
   690  			// as it is no longer needed.
   691  			if virtualState == vDel {
   692  				d._deleteVirtual(name)
   693  			}
   694  		}
   695  	}
   696  }
   697  
   698  // update d.items and if dirTree is not nil update each dir in the DirTree below this one and
   699  // set the last read time - must be called with the lock held
   700  func (d *Dir) _readDirFromEntries(entries fs.DirEntries, dirTree dirtree.DirTree, when time.Time) error {
   701  	var err error
   702  	mv := d._newManageVirtuals()
   703  	for _, entry := range entries {
   704  		name := path.Base(entry.Remote())
   705  		if name == "." || name == ".." {
   706  			continue
   707  		}
   708  		node := d.items[name]
   709  		if mv.add(d, name) {
   710  			continue
   711  		}
   712  		switch item := entry.(type) {
   713  		case fs.Object:
   714  			obj := item
   715  			// Reuse old file value if it exists
   716  			if file, ok := node.(*File); node != nil && ok {
   717  				file.setObjectNoUpdate(obj)
   718  			} else {
   719  				node = newFile(d, d.path, obj, name)
   720  			}
   721  		case fs.Directory:
   722  			// Reuse old dir value if it exists
   723  			if node == nil || !node.IsDir() {
   724  				node = newDir(d.vfs, d.f, d, item)
   725  			}
   726  			dir := node.(*Dir)
   727  			dir.mu.Lock()
   728  			dir.modTime = item.ModTime(context.TODO())
   729  			if dirTree != nil {
   730  				err = dir._readDirFromDirTree(dirTree, when)
   731  				if err != nil {
   732  					dir.read = time.Time{}
   733  				} else {
   734  					dir.read = when
   735  					dir.cleanupTimer.Reset(d.vfs.Opt.DirCacheTime * 2)
   736  				}
   737  			}
   738  			dir.mu.Unlock()
   739  			if err != nil {
   740  				return err
   741  			}
   742  		default:
   743  			err = fmt.Errorf("unknown type %T", item)
   744  			fs.Errorf(d, "readDir error: %v", err)
   745  			return err
   746  		}
   747  		d.items[name] = node
   748  	}
   749  	mv.end(d)
   750  	return nil
   751  }
   752  
   753  // readDirTree forces a refresh of the complete directory tree
   754  func (d *Dir) readDirTree() error {
   755  	d.mu.RLock()
   756  	f, path := d.f, d.path
   757  	d.mu.RUnlock()
   758  	when := time.Now()
   759  	fs.Debugf(path, "Reading directory tree")
   760  	dt, err := walk.NewDirTree(context.TODO(), f, path, false, -1)
   761  	if err != nil {
   762  		return err
   763  	}
   764  	d.mu.Lock()
   765  	defer d.mu.Unlock()
   766  	d.read = time.Time{}
   767  	err = d._readDirFromDirTree(dt, when)
   768  	if err != nil {
   769  		return err
   770  	}
   771  	fs.Debugf(d.path, "Reading directory tree done in %s", time.Since(when))
   772  	d.read = when
   773  	d.cleanupTimer.Reset(d.vfs.Opt.DirCacheTime * 2)
   774  	return nil
   775  }
   776  
   777  // readDir forces a refresh of the directory
   778  func (d *Dir) readDir() error {
   779  	d.mu.Lock()
   780  	defer d.mu.Unlock()
   781  	d.read = time.Time{}
   782  	return d._readDir()
   783  }
   784  
   785  // stat a single item in the directory
   786  //
   787  // returns ENOENT if not found.
   788  // returns a custom error if directory on a case-insensitive file system
   789  // contains files with names that differ only by case.
   790  func (d *Dir) stat(leaf string) (Node, error) {
   791  	d.mu.Lock()
   792  	defer d.mu.Unlock()
   793  	err := d._readDir()
   794  	if err != nil {
   795  		return nil, err
   796  	}
   797  	item, ok := d.items[leaf]
   798  
   799  	ci := fs.GetConfig(context.TODO())
   800  	normUnicode := !ci.NoUnicodeNormalization
   801  	normCase := ci.IgnoreCaseSync || d.vfs.Opt.CaseInsensitive
   802  	if !ok && (normUnicode || normCase) {
   803  		leafNormalized := operations.ToNormal(leaf, normUnicode, normCase) // this handles both case and unicode normalization
   804  		for name, node := range d.items {
   805  			if operations.ToNormal(name, normUnicode, normCase) == leafNormalized {
   806  				if ok {
   807  					// duplicate normalized match is an error
   808  					return nil, fmt.Errorf("duplicate filename %q detected with case/unicode normalization settings", leaf)
   809  				}
   810  				// found a normalized match
   811  				ok = true
   812  				item = node
   813  			}
   814  		}
   815  	}
   816  
   817  	if !ok {
   818  		return nil, ENOENT
   819  	}
   820  	return item, nil
   821  }
   822  
   823  // Check to see if a directory is empty
   824  func (d *Dir) isEmpty() (bool, error) {
   825  	d.mu.Lock()
   826  	defer d.mu.Unlock()
   827  	err := d._readDir()
   828  	if err != nil {
   829  		return false, err
   830  	}
   831  	return len(d.items) == 0, nil
   832  }
   833  
   834  // ModTime returns the modification time of the directory
   835  func (d *Dir) ModTime() time.Time {
   836  	d.modTimeMu.Lock()
   837  	defer d.modTimeMu.Unlock()
   838  	// fs.Debugf(d.path, "Dir.ModTime %v", d.modTime)
   839  	return d.modTime
   840  }
   841  
   842  // Size of the directory
   843  func (d *Dir) Size() int64 {
   844  	return 0
   845  }
   846  
   847  // SetModTime sets the modTime for this dir
   848  func (d *Dir) SetModTime(modTime time.Time) error {
   849  	if d.vfs.Opt.ReadOnly {
   850  		return EROFS
   851  	}
   852  	d.modTimeMu.Lock()
   853  	d.modTime = modTime
   854  	d.modTimeMu.Unlock()
   855  	return nil
   856  }
   857  
   858  func (d *Dir) cachedDir(relativePath string) (dir *Dir) {
   859  	dir, _ = d.cachedNode(relativePath).(*Dir)
   860  	return
   861  }
   862  
   863  func (d *Dir) cachedNode(relativePath string) Node {
   864  	segments := strings.Split(strings.Trim(relativePath, "/"), "/")
   865  	var node Node = d
   866  	for _, s := range segments {
   867  		if s == "" {
   868  			continue
   869  		}
   870  		if dir, ok := node.(*Dir); ok {
   871  			dir.mu.Lock()
   872  			node = dir.items[s]
   873  			dir.mu.Unlock()
   874  
   875  			if node != nil {
   876  				continue
   877  			}
   878  		}
   879  		return nil
   880  	}
   881  
   882  	return node
   883  }
   884  
   885  // Stat looks up a specific entry in the receiver.
   886  //
   887  // Stat should return a Node corresponding to the entry.  If the
   888  // name does not exist in the directory, Stat should return ENOENT.
   889  //
   890  // Stat need not to handle the names "." and "..".
   891  func (d *Dir) Stat(name string) (node Node, err error) {
   892  	// fs.Debugf(path, "Dir.Stat")
   893  	node, err = d.stat(name)
   894  	if err != nil {
   895  		if err != ENOENT {
   896  			fs.Errorf(d, "Dir.Stat error: %v", err)
   897  		}
   898  		return nil, err
   899  	}
   900  	// fs.Debugf(path, "Dir.Stat OK")
   901  	return node, nil
   902  }
   903  
   904  // ReadDirAll reads the contents of the directory sorted
   905  func (d *Dir) ReadDirAll() (items Nodes, err error) {
   906  	// fs.Debugf(d.path, "Dir.ReadDirAll")
   907  	d.mu.Lock()
   908  	err = d._readDir()
   909  	if err != nil {
   910  		fs.Debugf(d.path, "Dir.ReadDirAll error: %v", err)
   911  		d.mu.Unlock()
   912  		return nil, err
   913  	}
   914  	for _, item := range d.items {
   915  		items = append(items, item)
   916  	}
   917  	d.mu.Unlock()
   918  	sort.Sort(items)
   919  	// fs.Debugf(d.path, "Dir.ReadDirAll OK with %d entries", len(items))
   920  	return items, nil
   921  }
   922  
   923  // accessModeMask masks off the read modes from the flags
   924  const accessModeMask = (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)
   925  
   926  // Open the directory according to the flags provided
   927  func (d *Dir) Open(flags int) (fd Handle, err error) {
   928  	rdwrMode := flags & accessModeMask
   929  	if rdwrMode != os.O_RDONLY {
   930  		fs.Errorf(d, "Can only open directories read only")
   931  		return nil, EPERM
   932  	}
   933  	return newDirHandle(d), nil
   934  }
   935  
   936  // Create makes a new file node
   937  func (d *Dir) Create(name string, flags int) (*File, error) {
   938  	// fs.Debugf(path, "Dir.Create")
   939  	// Return existing node if one exists
   940  	node, err := d.stat(name)
   941  	switch err {
   942  	case ENOENT:
   943  		// not found, carry on
   944  	case nil:
   945  		// found so check what it is
   946  		if node.IsFile() {
   947  			return node.(*File), err
   948  		}
   949  		return nil, EEXIST // EISDIR would be better but we don't have that
   950  	default:
   951  		// a different error - report
   952  		fs.Errorf(d, "Dir.Create stat failed: %v", err)
   953  		return nil, err
   954  	}
   955  	// node doesn't exist so create it
   956  	if d.vfs.Opt.ReadOnly {
   957  		return nil, EROFS
   958  	}
   959  	if err = d.SetModTime(time.Now()); err != nil {
   960  		fs.Errorf(d, "Dir.Create failed to set modtime on parent dir: %v", err)
   961  		return nil, err
   962  	}
   963  	// This gets added to the directory when the file is opened for write
   964  	return newFile(d, d.Path(), nil, name), nil
   965  }
   966  
   967  // Mkdir creates a new directory
   968  func (d *Dir) Mkdir(name string) (*Dir, error) {
   969  	if d.vfs.Opt.ReadOnly {
   970  		return nil, EROFS
   971  	}
   972  	path := path.Join(d.path, name)
   973  	node, err := d.stat(name)
   974  	switch err {
   975  	case ENOENT:
   976  		// not found, carry on
   977  	case nil:
   978  		// found so check what it is
   979  		if node.IsDir() {
   980  			return node.(*Dir), err
   981  		}
   982  		return nil, EEXIST
   983  	default:
   984  		// a different error - report
   985  		fs.Errorf(d, "Dir.Mkdir failed to read directory: %v", err)
   986  		return nil, err
   987  	}
   988  	// fs.Debugf(path, "Dir.Mkdir")
   989  	err = d.f.Mkdir(context.TODO(), path)
   990  	if err != nil {
   991  		fs.Errorf(d, "Dir.Mkdir failed to create directory: %v", err)
   992  		return nil, err
   993  	}
   994  	fsDir := fs.NewDir(path, time.Now())
   995  	dir := newDir(d.vfs, d.f, d, fsDir)
   996  	d.addObject(dir)
   997  	if err = d.SetModTime(time.Now()); err != nil {
   998  		fs.Errorf(d, "Dir.Mkdir failed to set modtime on parent dir: %v", err)
   999  		return nil, err
  1000  	}
  1001  	// fs.Debugf(path, "Dir.Mkdir OK")
  1002  	return dir, nil
  1003  }
  1004  
  1005  // Remove the directory
  1006  func (d *Dir) Remove() error {
  1007  	if d.vfs.Opt.ReadOnly {
  1008  		return EROFS
  1009  	}
  1010  	// Check directory is empty first
  1011  	empty, err := d.isEmpty()
  1012  	if err != nil {
  1013  		fs.Errorf(d, "Dir.Remove dir error: %v", err)
  1014  		return err
  1015  	}
  1016  	if !empty {
  1017  		fs.Errorf(d, "Dir.Remove not empty")
  1018  		return ENOTEMPTY
  1019  	}
  1020  	// remove directory
  1021  	err = d.f.Rmdir(context.TODO(), d.path)
  1022  	if err != nil {
  1023  		fs.Errorf(d, "Dir.Remove failed to remove directory: %v", err)
  1024  		return err
  1025  	}
  1026  	// Remove the item from the parent directory listing
  1027  	if d.parent != nil {
  1028  		d.parent.delObject(d.Name())
  1029  	}
  1030  	return nil
  1031  }
  1032  
  1033  // RemoveAll removes the directory and any contents recursively
  1034  func (d *Dir) RemoveAll() error {
  1035  	if d.vfs.Opt.ReadOnly {
  1036  		return EROFS
  1037  	}
  1038  	// Remove contents of the directory
  1039  	nodes, err := d.ReadDirAll()
  1040  	if err != nil {
  1041  		fs.Errorf(d, "Dir.RemoveAll failed to read directory: %v", err)
  1042  		return err
  1043  	}
  1044  	for _, node := range nodes {
  1045  		err = node.RemoveAll()
  1046  		if err != nil {
  1047  			fs.Errorf(node.Path(), "Dir.RemoveAll failed to remove: %v", err)
  1048  			return err
  1049  		}
  1050  	}
  1051  	return d.Remove()
  1052  }
  1053  
  1054  // DirEntry returns the underlying fs.DirEntry
  1055  func (d *Dir) DirEntry() (entry fs.DirEntry) {
  1056  	return d.entry
  1057  }
  1058  
  1059  // RemoveName removes the entry with the given name from the receiver,
  1060  // which must be a directory.  The entry to be removed may correspond
  1061  // to a file (unlink) or to a directory (rmdir).
  1062  func (d *Dir) RemoveName(name string) error {
  1063  	if d.vfs.Opt.ReadOnly {
  1064  		return EROFS
  1065  	}
  1066  	// fs.Debugf(path, "Dir.Remove")
  1067  	node, err := d.stat(name)
  1068  	if err != nil {
  1069  		fs.Errorf(d, "Dir.Remove error: %v", err)
  1070  		return err
  1071  	}
  1072  	if err = d.SetModTime(time.Now()); err != nil {
  1073  		fs.Errorf(d, "Dir.Remove failed to set modtime on parent dir: %v", err)
  1074  		return err
  1075  	}
  1076  	return node.Remove()
  1077  }
  1078  
  1079  // Rename the file
  1080  func (d *Dir) Rename(oldName, newName string, destDir *Dir) error {
  1081  	// fs.Debugf(d, "BEFORE\n%s", d.dump())
  1082  	if d.vfs.Opt.ReadOnly {
  1083  		return EROFS
  1084  	}
  1085  	oldPath := path.Join(d.path, oldName)
  1086  	newPath := path.Join(destDir.path, newName)
  1087  	// fs.Debugf(oldPath, "Dir.Rename to %q", newPath)
  1088  	oldNode, err := d.stat(oldName)
  1089  	if err != nil {
  1090  		fs.Errorf(oldPath, "Dir.Rename error: %v", err)
  1091  		return err
  1092  	}
  1093  	switch x := oldNode.DirEntry().(type) {
  1094  	case nil:
  1095  		if oldFile, ok := oldNode.(*File); ok {
  1096  			if err = oldFile.rename(context.TODO(), destDir, newName); err != nil {
  1097  				fs.Errorf(oldPath, "Dir.Rename error: %v", err)
  1098  				return err
  1099  			}
  1100  		} else {
  1101  			fs.Errorf(oldPath, "Dir.Rename can't rename open file that is not a vfs.File")
  1102  			return EPERM
  1103  		}
  1104  	case fs.Object:
  1105  		if oldFile, ok := oldNode.(*File); ok {
  1106  			if err = oldFile.rename(context.TODO(), destDir, newName); err != nil {
  1107  				fs.Errorf(oldPath, "Dir.Rename error: %v", err)
  1108  				return err
  1109  			}
  1110  		} else {
  1111  			err := fmt.Errorf("Fs %q can't rename file that is not a vfs.File", d.f)
  1112  			fs.Errorf(oldPath, "Dir.Rename error: %v", err)
  1113  			return err
  1114  		}
  1115  	case fs.Directory:
  1116  		features := d.f.Features()
  1117  		if features.DirMove == nil && features.Move == nil && features.Copy == nil {
  1118  			err := fmt.Errorf("Fs %q can't rename directories (no DirMove, Move or Copy)", d.f)
  1119  			fs.Errorf(oldPath, "Dir.Rename error: %v", err)
  1120  			return err
  1121  		}
  1122  		srcRemote := x.Remote()
  1123  		dstRemote := newPath
  1124  		err = operations.DirMove(context.TODO(), d.f, srcRemote, dstRemote)
  1125  		if err != nil {
  1126  			fs.Errorf(oldPath, "Dir.Rename error: %v", err)
  1127  			return err
  1128  		}
  1129  		newDir := fs.NewDirCopy(context.TODO(), x).SetRemote(newPath)
  1130  		// Update the node with the new details
  1131  		if oldNode != nil {
  1132  			if oldDir, ok := oldNode.(*Dir); ok {
  1133  				fs.Debugf(x, "Updating dir with %v %p", newDir, oldDir)
  1134  				oldDir.rename(destDir, newDir)
  1135  			}
  1136  		}
  1137  	default:
  1138  		err = fmt.Errorf("unknown type %T", oldNode)
  1139  		fs.Errorf(d.path, "Dir.Rename error: %v", err)
  1140  		return err
  1141  	}
  1142  
  1143  	// Show moved - delete from old dir and add to new
  1144  	d.delObject(oldName)
  1145  	destDir.addObject(oldNode)
  1146  	if err = d.SetModTime(time.Now()); err != nil {
  1147  		fs.Errorf(d, "Dir.Rename failed to set modtime on parent dir: %v", err)
  1148  		return err
  1149  	}
  1150  
  1151  	// fs.Debugf(newPath, "Dir.Rename renamed from %q", oldPath)
  1152  	// fs.Debugf(d, "AFTER\n%s", d.dump())
  1153  	return nil
  1154  }
  1155  
  1156  // Sync the directory
  1157  //
  1158  // Note that we don't do anything except return OK
  1159  func (d *Dir) Sync() error {
  1160  	return nil
  1161  }
  1162  
  1163  // VFS returns the instance of the VFS
  1164  func (d *Dir) VFS() *VFS {
  1165  	// No locking required
  1166  	return d.vfs
  1167  }
  1168  
  1169  // Fs returns the Fs that the Dir is on
  1170  func (d *Dir) Fs() fs.Fs {
  1171  	// No locking required
  1172  	return d.f
  1173  }
  1174  
  1175  // Truncate changes the size of the named file.
  1176  func (d *Dir) Truncate(size int64) error {
  1177  	return ENOSYS
  1178  }