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

     1  // +build linux darwin freebsd
     2  
     3  package mount
     4  
     5  import (
     6  	"context"
     7  	"os"
     8  	"time"
     9  
    10  	"bazil.org/fuse"
    11  	fusefs "bazil.org/fuse/fs"
    12  	"github.com/ncw/rclone/cmd/mountlib"
    13  	"github.com/ncw/rclone/fs/log"
    14  	"github.com/ncw/rclone/vfs"
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  // Dir represents a directory entry
    19  type Dir struct {
    20  	*vfs.Dir
    21  }
    22  
    23  // Check interface satisfied
    24  var _ fusefs.Node = (*Dir)(nil)
    25  
    26  // Attr updates the attributes of a directory
    27  func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) (err error) {
    28  	defer log.Trace(d, "")("attr=%+v, err=%v", a, &err)
    29  	a.Valid = mountlib.AttrTimeout
    30  	a.Gid = d.VFS().Opt.GID
    31  	a.Uid = d.VFS().Opt.UID
    32  	a.Mode = os.ModeDir | d.VFS().Opt.DirPerms
    33  	modTime := d.ModTime()
    34  	a.Atime = modTime
    35  	a.Mtime = modTime
    36  	a.Ctime = modTime
    37  	a.Crtime = modTime
    38  	// FIXME include Valid so get some caching?
    39  	// FIXME fs.Debugf(d.path, "Dir.Attr %+v", a)
    40  	return nil
    41  }
    42  
    43  // Check interface satisfied
    44  var _ fusefs.NodeSetattrer = (*Dir)(nil)
    45  
    46  // Setattr handles attribute changes from FUSE. Currently supports ModTime only.
    47  func (d *Dir) Setattr(ctx context.Context, req *fuse.SetattrRequest, resp *fuse.SetattrResponse) (err error) {
    48  	defer log.Trace(d, "stat=%+v", req)("err=%v", &err)
    49  	if d.VFS().Opt.NoModTime {
    50  		return nil
    51  	}
    52  
    53  	if req.Valid.MtimeNow() {
    54  		err = d.SetModTime(time.Now())
    55  	} else if req.Valid.Mtime() {
    56  		err = d.SetModTime(req.Mtime)
    57  	}
    58  
    59  	return translateError(err)
    60  }
    61  
    62  // Check interface satisfied
    63  var _ fusefs.NodeRequestLookuper = (*Dir)(nil)
    64  
    65  // Lookup looks up a specific entry in the receiver.
    66  //
    67  // Lookup should return a Node corresponding to the entry.  If the
    68  // name does not exist in the directory, Lookup should return ENOENT.
    69  //
    70  // Lookup need not to handle the names "." and "..".
    71  func (d *Dir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.LookupResponse) (node fusefs.Node, err error) {
    72  	defer log.Trace(d, "name=%q", req.Name)("node=%+v, err=%v", &node, &err)
    73  	mnode, err := d.Dir.Stat(req.Name)
    74  	if err != nil {
    75  		return nil, translateError(err)
    76  	}
    77  	resp.EntryValid = mountlib.AttrTimeout
    78  	switch x := mnode.(type) {
    79  	case *vfs.File:
    80  		return &File{x}, nil
    81  	case *vfs.Dir:
    82  		return &Dir{x}, nil
    83  	}
    84  	panic("bad type")
    85  }
    86  
    87  // Check interface satisfied
    88  var _ fusefs.HandleReadDirAller = (*Dir)(nil)
    89  
    90  // ReadDirAll reads the contents of the directory
    91  func (d *Dir) ReadDirAll(ctx context.Context) (dirents []fuse.Dirent, err error) {
    92  	itemsRead := -1
    93  	defer log.Trace(d, "")("item=%d, err=%v", &itemsRead, &err)
    94  	items, err := d.Dir.ReadDirAll()
    95  	if err != nil {
    96  		return nil, translateError(err)
    97  	}
    98  	for _, node := range items {
    99  		var dirent = fuse.Dirent{
   100  			// Inode FIXME ???
   101  			Type: fuse.DT_File,
   102  			Name: node.Name(),
   103  		}
   104  		if node.IsDir() {
   105  			dirent.Type = fuse.DT_Dir
   106  		}
   107  		dirents = append(dirents, dirent)
   108  	}
   109  	itemsRead = len(dirents)
   110  	return dirents, nil
   111  }
   112  
   113  var _ fusefs.NodeCreater = (*Dir)(nil)
   114  
   115  // Create makes a new file
   116  func (d *Dir) Create(ctx context.Context, req *fuse.CreateRequest, resp *fuse.CreateResponse) (node fusefs.Node, handle fusefs.Handle, err error) {
   117  	defer log.Trace(d, "name=%q", req.Name)("node=%v, handle=%v, err=%v", &node, &handle, &err)
   118  	file, err := d.Dir.Create(req.Name, int(req.Flags))
   119  	if err != nil {
   120  		return nil, nil, translateError(err)
   121  	}
   122  	fh, err := file.Open(int(req.Flags) | os.O_CREATE)
   123  	if err != nil {
   124  		return nil, nil, translateError(err)
   125  	}
   126  	return &File{file}, &FileHandle{fh}, err
   127  }
   128  
   129  var _ fusefs.NodeMkdirer = (*Dir)(nil)
   130  
   131  // Mkdir creates a new directory
   132  func (d *Dir) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (node fusefs.Node, err error) {
   133  	defer log.Trace(d, "name=%q", req.Name)("node=%+v, err=%v", &node, &err)
   134  	dir, err := d.Dir.Mkdir(req.Name)
   135  	if err != nil {
   136  		return nil, translateError(err)
   137  	}
   138  	return &Dir{dir}, nil
   139  }
   140  
   141  var _ fusefs.NodeRemover = (*Dir)(nil)
   142  
   143  // Remove removes the entry with the given name from
   144  // the receiver, which must be a directory.  The entry to be removed
   145  // may correspond to a file (unlink) or to a directory (rmdir).
   146  func (d *Dir) Remove(ctx context.Context, req *fuse.RemoveRequest) (err error) {
   147  	defer log.Trace(d, "name=%q", req.Name)("err=%v", &err)
   148  	err = d.Dir.RemoveName(req.Name)
   149  	if err != nil {
   150  		return translateError(err)
   151  	}
   152  	return nil
   153  }
   154  
   155  // Check interface satisfied
   156  var _ fusefs.NodeRenamer = (*Dir)(nil)
   157  
   158  // Rename the file
   159  func (d *Dir) Rename(ctx context.Context, req *fuse.RenameRequest, newDir fusefs.Node) (err error) {
   160  	defer log.Trace(d, "oldName=%q, newName=%q, newDir=%+v", req.OldName, req.NewName, newDir)("err=%v", &err)
   161  	destDir, ok := newDir.(*Dir)
   162  	if !ok {
   163  		return errors.Errorf("Unknown Dir type %T", newDir)
   164  	}
   165  
   166  	err = d.Dir.Rename(req.OldName, req.NewName, destDir.Dir)
   167  	if err != nil {
   168  		return translateError(err)
   169  	}
   170  
   171  	return nil
   172  }
   173  
   174  // Check interface satisfied
   175  var _ fusefs.NodeFsyncer = (*Dir)(nil)
   176  
   177  // Fsync the directory
   178  func (d *Dir) Fsync(ctx context.Context, req *fuse.FsyncRequest) (err error) {
   179  	defer log.Trace(d, "")("err=%v", &err)
   180  	err = d.Dir.Sync()
   181  	if err != nil {
   182  		return translateError(err)
   183  	}
   184  	return nil
   185  }
   186  
   187  // Check interface satisfied
   188  var _ fusefs.NodeLinker = (*Dir)(nil)
   189  
   190  // Link creates a new directory entry in the receiver based on an
   191  // existing Node. Receiver must be a directory.
   192  func (d *Dir) Link(ctx context.Context, req *fuse.LinkRequest, old fusefs.Node) (newNode fusefs.Node, err error) {
   193  	defer log.Trace(d, "req=%v, old=%v", req, old)("new=%v, err=%v", &newNode, &err)
   194  	return nil, fuse.ENOSYS
   195  }