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

     1  package vfs
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"path"
     7  	"sort"
     8  	"strings"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/ncw/rclone/fs"
    13  	"github.com/ncw/rclone/fs/dirtree"
    14  	"github.com/ncw/rclone/fs/list"
    15  	"github.com/ncw/rclone/fs/operations"
    16  	"github.com/ncw/rclone/fs/walk"
    17  	"github.com/pkg/errors"
    18  )
    19  
    20  // Dir represents a directory entry
    21  type Dir struct {
    22  	vfs     *VFS
    23  	inode   uint64 // inode number
    24  	f       fs.Fs
    25  	parent  *Dir // parent, nil for root
    26  	path    string
    27  	modTime time.Time
    28  	entry   fs.Directory
    29  	mu      sync.Mutex      // protects the following
    30  	read    time.Time       // time directory entry last read
    31  	items   map[string]Node // directory entries - can be empty but not nil
    32  }
    33  
    34  func newDir(vfs *VFS, f fs.Fs, parent *Dir, fsDir fs.Directory) *Dir {
    35  	return &Dir{
    36  		vfs:     vfs,
    37  		f:       f,
    38  		parent:  parent,
    39  		entry:   fsDir,
    40  		path:    fsDir.Remote(),
    41  		modTime: fsDir.ModTime(context.TODO()),
    42  		inode:   newInode(),
    43  		items:   make(map[string]Node),
    44  	}
    45  }
    46  
    47  // String converts it to printablee
    48  func (d *Dir) String() string {
    49  	if d == nil {
    50  		return "<nil *Dir>"
    51  	}
    52  	return d.path + "/"
    53  }
    54  
    55  // IsFile returns false for Dir - satisfies Node interface
    56  func (d *Dir) IsFile() bool {
    57  	return false
    58  }
    59  
    60  // IsDir returns true for Dir - satisfies Node interface
    61  func (d *Dir) IsDir() bool {
    62  	return true
    63  }
    64  
    65  // Mode bits of the directory - satisfies Node interface
    66  func (d *Dir) Mode() (mode os.FileMode) {
    67  	return d.vfs.Opt.DirPerms
    68  }
    69  
    70  // Name (base) of the directory - satisfies Node interface
    71  func (d *Dir) Name() (name string) {
    72  	name = path.Base(d.path)
    73  	if name == "." {
    74  		name = "/"
    75  	}
    76  	return name
    77  }
    78  
    79  // Path of the directory - satisfies Node interface
    80  func (d *Dir) Path() (name string) {
    81  	return d.path
    82  }
    83  
    84  // Sys returns underlying data source (can be nil) - satisfies Node interface
    85  func (d *Dir) Sys() interface{} {
    86  	return nil
    87  }
    88  
    89  // Inode returns the inode number - satisfies Node interface
    90  func (d *Dir) Inode() uint64 {
    91  	return d.inode
    92  }
    93  
    94  // Node returns the Node assocuated with this - satisfies Noder interface
    95  func (d *Dir) Node() Node {
    96  	return d
    97  }
    98  
    99  // ForgetAll ensures the directory and all its children are purged
   100  // from the cache.
   101  func (d *Dir) ForgetAll() {
   102  	d.ForgetPath("", fs.EntryDirectory)
   103  }
   104  
   105  // ForgetPath clears the cache for itself and all subdirectories if
   106  // they match the given path. The path is specified relative from the
   107  // directory it is called from. The cache of the parent directory is
   108  // marked as stale, but not cleared otherwise.
   109  // It is not possible to traverse the directory tree upwards, i.e.
   110  // you cannot clear the cache for the Dir's ancestors or siblings.
   111  func (d *Dir) ForgetPath(relativePath string, entryType fs.EntryType) {
   112  	if absPath := path.Join(d.path, relativePath); absPath != "" {
   113  		parent := path.Dir(absPath)
   114  		if parent == "." || parent == "/" {
   115  			parent = ""
   116  		}
   117  		parentNode := d.vfs.root.cachedNode(parent)
   118  		if dir, ok := parentNode.(*Dir); ok {
   119  			dir.mu.Lock()
   120  			if !dir.read.IsZero() {
   121  				fs.Debugf(dir.path, "invalidating directory cache")
   122  				dir.read = time.Time{}
   123  			}
   124  			dir.mu.Unlock()
   125  		}
   126  	}
   127  
   128  	if entryType == fs.EntryDirectory {
   129  		if dir := d.cachedDir(relativePath); dir != nil {
   130  			dir.walk(func(dir *Dir) {
   131  				fs.Debugf(dir.path, "forgetting directory cache")
   132  				dir.read = time.Time{}
   133  				dir.items = make(map[string]Node)
   134  			})
   135  		}
   136  	}
   137  }
   138  
   139  // walk runs a function on all cached directories. It will be called
   140  // on a directory's children first.
   141  func (d *Dir) walk(fun func(*Dir)) {
   142  	d.mu.Lock()
   143  	defer d.mu.Unlock()
   144  	for _, node := range d.items {
   145  		if dir, ok := node.(*Dir); ok {
   146  			dir.walk(fun)
   147  		}
   148  	}
   149  
   150  	fun(d)
   151  }
   152  
   153  // stale returns true if the directory contents will be read the next
   154  // time it is accessed. stale must be called with d.mu held.
   155  func (d *Dir) stale(when time.Time) bool {
   156  	_, stale := d.age(when)
   157  	return stale
   158  }
   159  
   160  // age returns the duration since the last time the directory contents
   161  // was read and the content is cosidered stale. age will be 0 and
   162  // stale true if the last read time is empty.
   163  // age must be called with d.mu held.
   164  func (d *Dir) age(when time.Time) (age time.Duration, stale bool) {
   165  	if d.read.IsZero() {
   166  		return age, true
   167  	}
   168  	age = when.Sub(d.read)
   169  	stale = age > d.vfs.Opt.DirCacheTime
   170  	return
   171  }
   172  
   173  // rename should be called after the directory is renamed
   174  //
   175  // Reset the directory to new state, discarding all the objects and
   176  // reading everything again
   177  func (d *Dir) rename(newParent *Dir, fsDir fs.Directory) {
   178  	d.ForgetAll()
   179  	d.parent = newParent
   180  	d.entry = fsDir
   181  	d.path = fsDir.Remote()
   182  	d.modTime = fsDir.ModTime(context.TODO())
   183  	d.read = time.Time{}
   184  }
   185  
   186  // addObject adds a new object or directory to the directory
   187  //
   188  // note that we add new objects rather than updating old ones
   189  func (d *Dir) addObject(node Node) {
   190  	d.mu.Lock()
   191  	d.items[node.Name()] = node
   192  	d.mu.Unlock()
   193  }
   194  
   195  // delObject removes an object from the directory
   196  func (d *Dir) delObject(leaf string) {
   197  	d.mu.Lock()
   198  	delete(d.items, leaf)
   199  	d.mu.Unlock()
   200  }
   201  
   202  // read the directory and sets d.items - must be called with the lock held
   203  func (d *Dir) _readDir() error {
   204  	when := time.Now()
   205  	if age, stale := d.age(when); stale {
   206  		if age != 0 {
   207  			fs.Debugf(d.path, "Re-reading directory (%v old)", age)
   208  		}
   209  	} else {
   210  		return nil
   211  	}
   212  	entries, err := list.DirSorted(context.TODO(), d.f, false, d.path)
   213  	if err == fs.ErrorDirNotFound {
   214  		// We treat directory not found as empty because we
   215  		// create directories on the fly
   216  	} else if err != nil {
   217  		return err
   218  	}
   219  
   220  	err = d._readDirFromEntries(entries, nil, time.Time{})
   221  	if err != nil {
   222  		return err
   223  	}
   224  
   225  	d.read = when
   226  	return nil
   227  }
   228  
   229  // update d.items for each dir in the DirTree below this one and
   230  // set the last read time - must be called with the lock held
   231  func (d *Dir) _readDirFromDirTree(dirTree dirtree.DirTree, when time.Time) error {
   232  	return d._readDirFromEntries(dirTree[d.path], dirTree, when)
   233  }
   234  
   235  // update d.items and if dirTree is not nil update each dir in the DirTree below this one and
   236  // set the last read time - must be called with the lock held
   237  func (d *Dir) _readDirFromEntries(entries fs.DirEntries, dirTree dirtree.DirTree, when time.Time) error {
   238  	var err error
   239  	// Cache the items by name
   240  	found := make(map[string]struct{})
   241  	for _, entry := range entries {
   242  		name := path.Base(entry.Remote())
   243  		if name == "." || name == ".." {
   244  			continue
   245  		}
   246  		node := d.items[name]
   247  		found[name] = struct{}{}
   248  		switch item := entry.(type) {
   249  		case fs.Object:
   250  			obj := item
   251  			// Reuse old file value if it exists
   252  			if file, ok := node.(*File); node != nil && ok {
   253  				file.setObjectNoUpdate(obj)
   254  			} else {
   255  				node = newFile(d, obj, name)
   256  			}
   257  		case fs.Directory:
   258  			// Reuse old dir value if it exists
   259  			if node == nil || !node.IsDir() {
   260  				node = newDir(d.vfs, d.f, d, item)
   261  			}
   262  			if dirTree != nil {
   263  				dir := node.(*Dir)
   264  				dir.mu.Lock()
   265  				err = dir._readDirFromDirTree(dirTree, when)
   266  				if err != nil {
   267  					dir.read = time.Time{}
   268  				} else {
   269  					dir.read = when
   270  				}
   271  				dir.mu.Unlock()
   272  				if err != nil {
   273  					return err
   274  				}
   275  			}
   276  		default:
   277  			err = errors.Errorf("unknown type %T", item)
   278  			fs.Errorf(d, "readDir error: %v", err)
   279  			return err
   280  		}
   281  		d.items[name] = node
   282  	}
   283  	// delete unused entries
   284  	for name := range d.items {
   285  		if _, ok := found[name]; !ok {
   286  			delete(d.items, name)
   287  		}
   288  	}
   289  	return nil
   290  }
   291  
   292  // readDirTree forces a refresh of the complete directory tree
   293  func (d *Dir) readDirTree() error {
   294  	d.mu.Lock()
   295  	f, path := d.f, d.path
   296  	d.mu.Unlock()
   297  	when := time.Now()
   298  	fs.Debugf(path, "Reading directory tree")
   299  	dt, err := walk.NewDirTree(context.TODO(), f, path, false, -1)
   300  	if err != nil {
   301  		return err
   302  	}
   303  	d.mu.Lock()
   304  	defer d.mu.Unlock()
   305  	d.read = time.Time{}
   306  	err = d._readDirFromDirTree(dt, when)
   307  	if err != nil {
   308  		return err
   309  	}
   310  	fs.Debugf(d.path, "Reading directory tree done in %s", time.Since(when))
   311  	d.read = when
   312  	return nil
   313  }
   314  
   315  // readDir forces a refresh of the directory
   316  func (d *Dir) readDir() error {
   317  	d.mu.Lock()
   318  	defer d.mu.Unlock()
   319  	d.read = time.Time{}
   320  	return d._readDir()
   321  }
   322  
   323  // stat a single item in the directory
   324  //
   325  // returns ENOENT if not found.
   326  func (d *Dir) stat(leaf string) (Node, error) {
   327  	d.mu.Lock()
   328  	defer d.mu.Unlock()
   329  	err := d._readDir()
   330  	if err != nil {
   331  		return nil, err
   332  	}
   333  	item, ok := d.items[leaf]
   334  	if !ok {
   335  		return nil, ENOENT
   336  	}
   337  	return item, nil
   338  }
   339  
   340  // Check to see if a directory is empty
   341  func (d *Dir) isEmpty() (bool, error) {
   342  	d.mu.Lock()
   343  	defer d.mu.Unlock()
   344  	err := d._readDir()
   345  	if err != nil {
   346  		return false, err
   347  	}
   348  	return len(d.items) == 0, nil
   349  }
   350  
   351  // ModTime returns the modification time of the directory
   352  func (d *Dir) ModTime() time.Time {
   353  	// fs.Debugf(d.path, "Dir.ModTime %v", d.modTime)
   354  	return d.modTime
   355  }
   356  
   357  // Size of the directory
   358  func (d *Dir) Size() int64 {
   359  	return 0
   360  }
   361  
   362  // SetModTime sets the modTime for this dir
   363  func (d *Dir) SetModTime(modTime time.Time) error {
   364  	if d.vfs.Opt.ReadOnly {
   365  		return EROFS
   366  	}
   367  	d.mu.Lock()
   368  	defer d.mu.Unlock()
   369  	d.modTime = modTime
   370  	return nil
   371  }
   372  
   373  func (d *Dir) cachedDir(relativePath string) (dir *Dir) {
   374  	dir, _ = d.cachedNode(relativePath).(*Dir)
   375  	return
   376  }
   377  
   378  func (d *Dir) cachedNode(relativePath string) Node {
   379  	segments := strings.Split(strings.Trim(relativePath, "/"), "/")
   380  	var node Node = d
   381  	for _, s := range segments {
   382  		if s == "" {
   383  			continue
   384  		}
   385  		if dir, ok := node.(*Dir); ok {
   386  			dir.mu.Lock()
   387  			node = dir.items[s]
   388  			dir.mu.Unlock()
   389  
   390  			if node != nil {
   391  				continue
   392  			}
   393  		}
   394  		return nil
   395  	}
   396  
   397  	return node
   398  }
   399  
   400  // Stat looks up a specific entry in the receiver.
   401  //
   402  // Stat should return a Node corresponding to the entry.  If the
   403  // name does not exist in the directory, Stat should return ENOENT.
   404  //
   405  // Stat need not to handle the names "." and "..".
   406  func (d *Dir) Stat(name string) (node Node, err error) {
   407  	// fs.Debugf(path, "Dir.Stat")
   408  	node, err = d.stat(name)
   409  	if err != nil {
   410  		if err != ENOENT {
   411  			fs.Errorf(d, "Dir.Stat error: %v", err)
   412  		}
   413  		return nil, err
   414  	}
   415  	// fs.Debugf(path, "Dir.Stat OK")
   416  	return node, nil
   417  }
   418  
   419  // ReadDirAll reads the contents of the directory sorted
   420  func (d *Dir) ReadDirAll() (items Nodes, err error) {
   421  	// fs.Debugf(d.path, "Dir.ReadDirAll")
   422  	d.mu.Lock()
   423  	defer d.mu.Unlock()
   424  	err = d._readDir()
   425  	if err != nil {
   426  		fs.Debugf(d.path, "Dir.ReadDirAll error: %v", err)
   427  		return nil, err
   428  	}
   429  	for _, item := range d.items {
   430  		items = append(items, item)
   431  	}
   432  	sort.Sort(items)
   433  	// fs.Debugf(d.path, "Dir.ReadDirAll OK with %d entries", len(items))
   434  	return items, nil
   435  }
   436  
   437  // accessModeMask masks off the read modes from the flags
   438  const accessModeMask = (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)
   439  
   440  // Open the directory according to the flags provided
   441  func (d *Dir) Open(flags int) (fd Handle, err error) {
   442  	rdwrMode := flags & accessModeMask
   443  	if rdwrMode != os.O_RDONLY {
   444  		fs.Errorf(d, "Can only open directories read only")
   445  		return nil, EPERM
   446  	}
   447  	return newDirHandle(d), nil
   448  }
   449  
   450  // Create makes a new file node
   451  func (d *Dir) Create(name string, flags int) (*File, error) {
   452  	// fs.Debugf(path, "Dir.Create")
   453  	if d.vfs.Opt.ReadOnly {
   454  		return nil, EROFS
   455  	}
   456  	// This gets added to the directory when the file is opened for write
   457  	return newFile(d, nil, name), nil
   458  }
   459  
   460  // Mkdir creates a new directory
   461  func (d *Dir) Mkdir(name string) (*Dir, error) {
   462  	if d.vfs.Opt.ReadOnly {
   463  		return nil, EROFS
   464  	}
   465  	path := path.Join(d.path, name)
   466  	node, err := d.stat(name)
   467  	switch err {
   468  	case ENOENT:
   469  		// not found, carry on
   470  	case nil:
   471  		// found so check what it is
   472  		if node.IsDir() {
   473  			return node.(*Dir), err
   474  		}
   475  		return nil, EEXIST
   476  	default:
   477  		// a different error - report
   478  		fs.Errorf(d, "Dir.Mkdir failed to read directory: %v", err)
   479  		return nil, err
   480  	}
   481  	// fs.Debugf(path, "Dir.Mkdir")
   482  	err = d.f.Mkdir(context.TODO(), path)
   483  	if err != nil {
   484  		fs.Errorf(d, "Dir.Mkdir failed to create directory: %v", err)
   485  		return nil, err
   486  	}
   487  	fsDir := fs.NewDir(path, time.Now())
   488  	dir := newDir(d.vfs, d.f, d, fsDir)
   489  	d.addObject(dir)
   490  	// fs.Debugf(path, "Dir.Mkdir OK")
   491  	return dir, nil
   492  }
   493  
   494  // Remove the directory
   495  func (d *Dir) Remove() error {
   496  	if d.vfs.Opt.ReadOnly {
   497  		return EROFS
   498  	}
   499  	// Check directory is empty first
   500  	empty, err := d.isEmpty()
   501  	if err != nil {
   502  		fs.Errorf(d, "Dir.Remove dir error: %v", err)
   503  		return err
   504  	}
   505  	if !empty {
   506  		fs.Errorf(d, "Dir.Remove not empty")
   507  		return ENOTEMPTY
   508  	}
   509  	// remove directory
   510  	err = d.f.Rmdir(context.TODO(), d.path)
   511  	if err != nil {
   512  		fs.Errorf(d, "Dir.Remove failed to remove directory: %v", err)
   513  		return err
   514  	}
   515  	// Remove the item from the parent directory listing
   516  	if d.parent != nil {
   517  		d.parent.delObject(d.Name())
   518  	}
   519  	return nil
   520  }
   521  
   522  // RemoveAll removes the directory and any contents recursively
   523  func (d *Dir) RemoveAll() error {
   524  	if d.vfs.Opt.ReadOnly {
   525  		return EROFS
   526  	}
   527  	// Remove contents of the directory
   528  	nodes, err := d.ReadDirAll()
   529  	if err != nil {
   530  		fs.Errorf(d, "Dir.RemoveAll failed to read directory: %v", err)
   531  		return err
   532  	}
   533  	for _, node := range nodes {
   534  		err = node.RemoveAll()
   535  		if err != nil {
   536  			fs.Errorf(node.Path(), "Dir.RemoveAll failed to remove: %v", err)
   537  			return err
   538  		}
   539  	}
   540  	return d.Remove()
   541  }
   542  
   543  // DirEntry returns the underlying fs.DirEntry
   544  func (d *Dir) DirEntry() (entry fs.DirEntry) {
   545  	return d.entry
   546  }
   547  
   548  // RemoveName removes the entry with the given name from the receiver,
   549  // which must be a directory.  The entry to be removed may correspond
   550  // to a file (unlink) or to a directory (rmdir).
   551  func (d *Dir) RemoveName(name string) error {
   552  	if d.vfs.Opt.ReadOnly {
   553  		return EROFS
   554  	}
   555  	// fs.Debugf(path, "Dir.Remove")
   556  	node, err := d.stat(name)
   557  	if err != nil {
   558  		fs.Errorf(d, "Dir.Remove error: %v", err)
   559  		return err
   560  	}
   561  	return node.Remove()
   562  }
   563  
   564  // Rename the file
   565  func (d *Dir) Rename(oldName, newName string, destDir *Dir) error {
   566  	if d.vfs.Opt.ReadOnly {
   567  		return EROFS
   568  	}
   569  	oldPath := path.Join(d.path, oldName)
   570  	newPath := path.Join(destDir.path, newName)
   571  	// fs.Debugf(oldPath, "Dir.Rename to %q", newPath)
   572  	oldNode, err := d.stat(oldName)
   573  	if err != nil {
   574  		fs.Errorf(oldPath, "Dir.Rename error: %v", err)
   575  		return err
   576  	}
   577  	switch x := oldNode.DirEntry().(type) {
   578  	case nil:
   579  		if oldFile, ok := oldNode.(*File); ok {
   580  			if err = oldFile.rename(context.TODO(), destDir, newName); err != nil {
   581  				fs.Errorf(oldPath, "Dir.Rename error: %v", err)
   582  				return err
   583  			}
   584  		} else {
   585  			fs.Errorf(oldPath, "Dir.Rename can't rename open file that is not a vfs.File")
   586  			return EPERM
   587  		}
   588  	case fs.Object:
   589  		if oldFile, ok := oldNode.(*File); ok {
   590  			if err = oldFile.rename(context.TODO(), destDir, newName); err != nil {
   591  				fs.Errorf(oldPath, "Dir.Rename error: %v", err)
   592  				return err
   593  			}
   594  		} else {
   595  			err := errors.Errorf("Fs %q can't rename file that is not a vfs.File", d.f)
   596  			fs.Errorf(oldPath, "Dir.Rename error: %v", err)
   597  			return err
   598  		}
   599  	case fs.Directory:
   600  		features := d.f.Features()
   601  		if features.DirMove == nil && features.Move == nil && features.Copy == nil {
   602  			err := errors.Errorf("Fs %q can't rename directories (no DirMove, Move or Copy)", d.f)
   603  			fs.Errorf(oldPath, "Dir.Rename error: %v", err)
   604  			return err
   605  		}
   606  		srcRemote := x.Remote()
   607  		dstRemote := newPath
   608  		err = operations.DirMove(context.TODO(), d.f, srcRemote, dstRemote)
   609  		if err != nil {
   610  			fs.Errorf(oldPath, "Dir.Rename error: %v", err)
   611  			return err
   612  		}
   613  		newDir := fs.NewDirCopy(context.TODO(), x).SetRemote(newPath)
   614  		// Update the node with the new details
   615  		if oldNode != nil {
   616  			if oldDir, ok := oldNode.(*Dir); ok {
   617  				fs.Debugf(x, "Updating dir with %v %p", newDir, oldDir)
   618  				oldDir.rename(destDir, newDir)
   619  			}
   620  		}
   621  	default:
   622  		err = errors.Errorf("unknown type %T", oldNode)
   623  		fs.Errorf(d.path, "Dir.Rename error: %v", err)
   624  		return err
   625  	}
   626  
   627  	// Show moved - delete from old dir and add to new
   628  	d.delObject(oldName)
   629  	destDir.addObject(oldNode)
   630  
   631  	// fs.Debugf(newPath, "Dir.Rename renamed from %q", oldPath)
   632  	return nil
   633  }
   634  
   635  // Sync the directory
   636  //
   637  // Note that we don't do anything except return OK
   638  func (d *Dir) Sync() error {
   639  	return nil
   640  }
   641  
   642  // VFS returns the instance of the VFS
   643  func (d *Dir) VFS() *VFS {
   644  	return d.vfs
   645  }
   646  
   647  // Truncate changes the size of the named file.
   648  func (d *Dir) Truncate(size int64) error {
   649  	return ENOSYS
   650  }