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

     1  // +build cmount
     2  // +build cgo
     3  // +build linux darwin freebsd windows
     4  
     5  package cmount
     6  
     7  import (
     8  	"io"
     9  	"os"
    10  	"path"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/billziss-gh/cgofuse/fuse"
    15  	"github.com/ncw/rclone/cmd/mountlib"
    16  	"github.com/ncw/rclone/fs"
    17  	"github.com/ncw/rclone/fs/log"
    18  	"github.com/ncw/rclone/vfs"
    19  	"github.com/ncw/rclone/vfs/vfsflags"
    20  	"github.com/pkg/errors"
    21  )
    22  
    23  const fhUnset = ^uint64(0)
    24  
    25  // FS represents the top level filing system
    26  type FS struct {
    27  	VFS     *vfs.VFS
    28  	f       fs.Fs
    29  	ready   chan (struct{})
    30  	mu      sync.Mutex // to protect the below
    31  	handles []vfs.Handle
    32  }
    33  
    34  // NewFS makes a new FS
    35  func NewFS(f fs.Fs) *FS {
    36  	fsys := &FS{
    37  		VFS:   vfs.New(f, &vfsflags.Opt),
    38  		f:     f,
    39  		ready: make(chan (struct{})),
    40  	}
    41  	return fsys
    42  }
    43  
    44  // Open a handle returning an integer file handle
    45  func (fsys *FS) openHandle(handle vfs.Handle) (fh uint64) {
    46  	fsys.mu.Lock()
    47  	defer fsys.mu.Unlock()
    48  	var i int
    49  	var oldHandle vfs.Handle
    50  	for i, oldHandle = range fsys.handles {
    51  		if oldHandle == nil {
    52  			fsys.handles[i] = handle
    53  			goto found
    54  		}
    55  	}
    56  	fsys.handles = append(fsys.handles, handle)
    57  	i = len(fsys.handles) - 1
    58  found:
    59  	return uint64(i)
    60  }
    61  
    62  // get the handle for fh, call with the lock held
    63  func (fsys *FS) _getHandle(fh uint64) (i int, handle vfs.Handle, errc int) {
    64  	if fh > uint64(len(fsys.handles)) {
    65  		fs.Debugf(nil, "Bad file handle: too big: 0x%X", fh)
    66  		return i, nil, -fuse.EBADF
    67  	}
    68  	i = int(fh)
    69  	handle = fsys.handles[i]
    70  	if handle == nil {
    71  		fs.Debugf(nil, "Bad file handle: nil handle: 0x%X", fh)
    72  		return i, nil, -fuse.EBADF
    73  	}
    74  	return i, handle, 0
    75  }
    76  
    77  // Get the handle for the file handle
    78  func (fsys *FS) getHandle(fh uint64) (handle vfs.Handle, errc int) {
    79  	fsys.mu.Lock()
    80  	_, handle, errc = fsys._getHandle(fh)
    81  	fsys.mu.Unlock()
    82  	return
    83  }
    84  
    85  // Close the handle
    86  func (fsys *FS) closeHandle(fh uint64) (errc int) {
    87  	fsys.mu.Lock()
    88  	i, _, errc := fsys._getHandle(fh)
    89  	if errc == 0 {
    90  		fsys.handles[i] = nil
    91  	}
    92  	fsys.mu.Unlock()
    93  	return
    94  }
    95  
    96  // lookup a Node given a path
    97  func (fsys *FS) lookupNode(path string) (node vfs.Node, errc int) {
    98  	node, err := fsys.VFS.Stat(path)
    99  	return node, translateError(err)
   100  }
   101  
   102  // lookup a Dir given a path
   103  func (fsys *FS) lookupDir(path string) (dir *vfs.Dir, errc int) {
   104  	node, errc := fsys.lookupNode(path)
   105  	if errc != 0 {
   106  		return nil, errc
   107  	}
   108  	dir, ok := node.(*vfs.Dir)
   109  	if !ok {
   110  		return nil, -fuse.ENOTDIR
   111  	}
   112  	return dir, 0
   113  }
   114  
   115  // lookup a parent Dir given a path returning the dir and the leaf
   116  func (fsys *FS) lookupParentDir(filePath string) (leaf string, dir *vfs.Dir, errc int) {
   117  	parentDir, leaf := path.Split(filePath)
   118  	dir, errc = fsys.lookupDir(parentDir)
   119  	return leaf, dir, errc
   120  }
   121  
   122  // lookup a File given a path
   123  func (fsys *FS) lookupFile(path string) (file *vfs.File, errc int) {
   124  	node, errc := fsys.lookupNode(path)
   125  	if errc != 0 {
   126  		return nil, errc
   127  	}
   128  	file, ok := node.(*vfs.File)
   129  	if !ok {
   130  		return nil, -fuse.EISDIR
   131  	}
   132  	return file, 0
   133  }
   134  
   135  // get a node and handle from the path or from the fh if not fhUnset
   136  //
   137  // handle may be nil
   138  func (fsys *FS) getNode(path string, fh uint64) (node vfs.Node, handle vfs.Handle, errc int) {
   139  	if fh == fhUnset {
   140  		node, errc = fsys.lookupNode(path)
   141  	} else {
   142  		handle, errc = fsys.getHandle(fh)
   143  		if errc == 0 {
   144  			node = handle.Node()
   145  		}
   146  	}
   147  	return
   148  }
   149  
   150  // stat fills up the stat block for Node
   151  func (fsys *FS) stat(node vfs.Node, stat *fuse.Stat_t) (errc int) {
   152  	Size := uint64(node.Size())
   153  	Blocks := (Size + 511) / 512
   154  	modTime := node.ModTime()
   155  	Mode := node.Mode().Perm()
   156  	if node.IsDir() {
   157  		Mode |= fuse.S_IFDIR
   158  	} else {
   159  		Mode |= fuse.S_IFREG
   160  	}
   161  	//stat.Dev = 1
   162  	stat.Ino = node.Inode() // FIXME do we need to set the inode number?
   163  	stat.Mode = uint32(Mode)
   164  	stat.Nlink = 1
   165  	stat.Uid = fsys.VFS.Opt.UID
   166  	stat.Gid = fsys.VFS.Opt.GID
   167  	//stat.Rdev
   168  	stat.Size = int64(Size)
   169  	t := fuse.NewTimespec(modTime)
   170  	stat.Atim = t
   171  	stat.Mtim = t
   172  	stat.Ctim = t
   173  	stat.Blksize = 512
   174  	stat.Blocks = int64(Blocks)
   175  	stat.Birthtim = t
   176  	// fs.Debugf(nil, "stat = %+v", *stat)
   177  	return 0
   178  }
   179  
   180  // Init is called after the filesystem is ready
   181  func (fsys *FS) Init() {
   182  	defer log.Trace(fsys.f, "")("")
   183  	close(fsys.ready)
   184  }
   185  
   186  // Destroy is called when it is unmounted (note that depending on how
   187  // the file system is terminated the file system may not receive the
   188  // Destroy call).
   189  func (fsys *FS) Destroy() {
   190  	defer log.Trace(fsys.f, "")("")
   191  }
   192  
   193  // Getattr reads the attributes for path
   194  func (fsys *FS) Getattr(path string, stat *fuse.Stat_t, fh uint64) (errc int) {
   195  	defer log.Trace(path, "fh=0x%X", fh)("errc=%v", &errc)
   196  	node, _, errc := fsys.getNode(path, fh)
   197  	if errc == 0 {
   198  		errc = fsys.stat(node, stat)
   199  	}
   200  	return
   201  }
   202  
   203  // Opendir opens path as a directory
   204  func (fsys *FS) Opendir(path string) (errc int, fh uint64) {
   205  	defer log.Trace(path, "")("errc=%d, fh=0x%X", &errc, &fh)
   206  	handle, err := fsys.VFS.OpenFile(path, os.O_RDONLY, 0777)
   207  	if err != nil {
   208  		return translateError(err), fhUnset
   209  	}
   210  	return 0, fsys.openHandle(handle)
   211  }
   212  
   213  // Readdir reads the directory at dirPath
   214  func (fsys *FS) Readdir(dirPath string,
   215  	fill func(name string, stat *fuse.Stat_t, ofst int64) bool,
   216  	ofst int64,
   217  	fh uint64) (errc int) {
   218  	itemsRead := -1
   219  	defer log.Trace(dirPath, "ofst=%d, fh=0x%X", ofst, fh)("items=%d, errc=%d", &itemsRead, &errc)
   220  
   221  	node, errc := fsys.getHandle(fh)
   222  	if errc != 0 {
   223  		return errc
   224  	}
   225  
   226  	items, err := node.Readdir(-1)
   227  	if err != nil {
   228  		return translateError(err)
   229  	}
   230  
   231  	// Optionally, create a struct stat that describes the file as
   232  	// for getattr (but FUSE only looks at st_ino and the
   233  	// file-type bits of st_mode).
   234  	//
   235  	// FIXME If you call host.SetCapReaddirPlus() then WinFsp will
   236  	// use the full stat information - a Useful optimization on
   237  	// Windows.
   238  	//
   239  	// NB we are using the first mode for readdir: The readdir
   240  	// implementation ignores the offset parameter, and passes
   241  	// zero to the filler function's offset. The filler function
   242  	// will not return '1' (unless an error happens), so the whole
   243  	// directory is read in a single readdir operation.
   244  	fill(".", nil, 0)
   245  	fill("..", nil, 0)
   246  	for _, item := range items {
   247  		node, ok := item.(vfs.Node)
   248  		if ok {
   249  			fill(node.Name(), nil, 0)
   250  		}
   251  	}
   252  	itemsRead = len(items)
   253  	return 0
   254  }
   255  
   256  // Releasedir finished reading the directory
   257  func (fsys *FS) Releasedir(path string, fh uint64) (errc int) {
   258  	defer log.Trace(path, "fh=0x%X", fh)("errc=%d", &errc)
   259  	return fsys.closeHandle(fh)
   260  }
   261  
   262  // Statfs reads overall stats on the filessystem
   263  func (fsys *FS) Statfs(path string, stat *fuse.Statfs_t) (errc int) {
   264  	defer log.Trace(path, "")("stat=%+v, errc=%d", stat, &errc)
   265  	const blockSize = 4096
   266  	const fsBlocks = (1 << 50) / blockSize
   267  	stat.Blocks = fsBlocks  // Total data blocks in file system.
   268  	stat.Bfree = fsBlocks   // Free blocks in file system.
   269  	stat.Bavail = fsBlocks  // Free blocks in file system if you're not root.
   270  	stat.Files = 1E9        // Total files in file system.
   271  	stat.Ffree = 1E9        // Free files in file system.
   272  	stat.Bsize = blockSize  // Block size
   273  	stat.Namemax = 255      // Maximum file name length?
   274  	stat.Frsize = blockSize // Fragment size, smallest addressable data size in the file system.
   275  	total, used, free := fsys.VFS.Statfs()
   276  	if total >= 0 {
   277  		stat.Blocks = uint64(total) / blockSize
   278  	}
   279  	if used >= 0 {
   280  		stat.Bfree = stat.Blocks - uint64(used)/blockSize
   281  	}
   282  	if free >= 0 {
   283  		stat.Bavail = uint64(free) / blockSize
   284  	}
   285  	mountlib.ClipBlocks(&stat.Blocks)
   286  	mountlib.ClipBlocks(&stat.Bfree)
   287  	mountlib.ClipBlocks(&stat.Bavail)
   288  	return 0
   289  }
   290  
   291  // Open opens a file
   292  func (fsys *FS) Open(path string, flags int) (errc int, fh uint64) {
   293  	defer log.Trace(path, "flags=0x%X", flags)("errc=%d, fh=0x%X", &errc, &fh)
   294  
   295  	// translate the fuse flags to os flags
   296  	flags = translateOpenFlags(flags)
   297  	handle, err := fsys.VFS.OpenFile(path, flags, 0777)
   298  	if err != nil {
   299  		return translateError(err), fhUnset
   300  	}
   301  
   302  	return 0, fsys.openHandle(handle)
   303  }
   304  
   305  // Create creates and opens a file.
   306  func (fsys *FS) Create(filePath string, flags int, mode uint32) (errc int, fh uint64) {
   307  	defer log.Trace(filePath, "flags=0x%X, mode=0%o", flags, mode)("errc=%d, fh=0x%X", &errc, &fh)
   308  	leaf, parentDir, errc := fsys.lookupParentDir(filePath)
   309  	if errc != 0 {
   310  		return errc, fhUnset
   311  	}
   312  	file, err := parentDir.Create(leaf, flags)
   313  	if err != nil {
   314  		return translateError(err), fhUnset
   315  	}
   316  	// translate the fuse flags to os flags
   317  	flags = translateOpenFlags(flags) | os.O_CREATE
   318  	handle, err := file.Open(flags)
   319  	if err != nil {
   320  		return translateError(err), fhUnset
   321  	}
   322  	return 0, fsys.openHandle(handle)
   323  }
   324  
   325  // Truncate truncates a file to size
   326  func (fsys *FS) Truncate(path string, size int64, fh uint64) (errc int) {
   327  	defer log.Trace(path, "size=%d, fh=0x%X", size, fh)("errc=%d", &errc)
   328  	node, handle, errc := fsys.getNode(path, fh)
   329  	if errc != 0 {
   330  		return errc
   331  	}
   332  	var err error
   333  	if handle != nil {
   334  		err = handle.Truncate(size)
   335  	} else {
   336  		err = node.Truncate(size)
   337  	}
   338  	if err != nil {
   339  		return translateError(err)
   340  	}
   341  	return 0
   342  }
   343  
   344  // Read data from file handle
   345  func (fsys *FS) Read(path string, buff []byte, ofst int64, fh uint64) (n int) {
   346  	defer log.Trace(path, "ofst=%d, fh=0x%X", ofst, fh)("n=%d", &n)
   347  	handle, errc := fsys.getHandle(fh)
   348  	if errc != 0 {
   349  		return errc
   350  	}
   351  	n, err := handle.ReadAt(buff, ofst)
   352  	if err == io.EOF {
   353  	} else if err != nil {
   354  		return translateError(err)
   355  	}
   356  	return n
   357  }
   358  
   359  // Write data to file handle
   360  func (fsys *FS) Write(path string, buff []byte, ofst int64, fh uint64) (n int) {
   361  	defer log.Trace(path, "ofst=%d, fh=0x%X", ofst, fh)("n=%d", &n)
   362  	handle, errc := fsys.getHandle(fh)
   363  	if errc != 0 {
   364  		return errc
   365  	}
   366  	n, err := handle.WriteAt(buff, ofst)
   367  	if err != nil {
   368  		return translateError(err)
   369  	}
   370  	return n
   371  }
   372  
   373  // Flush flushes an open file descriptor or path
   374  func (fsys *FS) Flush(path string, fh uint64) (errc int) {
   375  	defer log.Trace(path, "fh=0x%X", fh)("errc=%d", &errc)
   376  	handle, errc := fsys.getHandle(fh)
   377  	if errc != 0 {
   378  		return errc
   379  	}
   380  	return translateError(handle.Flush())
   381  }
   382  
   383  // Release closes the file if still open
   384  func (fsys *FS) Release(path string, fh uint64) (errc int) {
   385  	defer log.Trace(path, "fh=0x%X", fh)("errc=%d", &errc)
   386  	handle, errc := fsys.getHandle(fh)
   387  	if errc != 0 {
   388  		return errc
   389  	}
   390  	_ = fsys.closeHandle(fh)
   391  	return translateError(handle.Release())
   392  }
   393  
   394  // Unlink removes a file.
   395  func (fsys *FS) Unlink(filePath string) (errc int) {
   396  	defer log.Trace(filePath, "")("errc=%d", &errc)
   397  	leaf, parentDir, errc := fsys.lookupParentDir(filePath)
   398  	if errc != 0 {
   399  		return errc
   400  	}
   401  	return translateError(parentDir.RemoveName(leaf))
   402  }
   403  
   404  // Mkdir creates a directory.
   405  func (fsys *FS) Mkdir(dirPath string, mode uint32) (errc int) {
   406  	defer log.Trace(dirPath, "mode=0%o", mode)("errc=%d", &errc)
   407  	leaf, parentDir, errc := fsys.lookupParentDir(dirPath)
   408  	if errc != 0 {
   409  		return errc
   410  	}
   411  	_, err := parentDir.Mkdir(leaf)
   412  	return translateError(err)
   413  }
   414  
   415  // Rmdir removes a directory
   416  func (fsys *FS) Rmdir(dirPath string) (errc int) {
   417  	defer log.Trace(dirPath, "")("errc=%d", &errc)
   418  	leaf, parentDir, errc := fsys.lookupParentDir(dirPath)
   419  	if errc != 0 {
   420  		return errc
   421  	}
   422  	return translateError(parentDir.RemoveName(leaf))
   423  }
   424  
   425  // Rename renames a file.
   426  func (fsys *FS) Rename(oldPath string, newPath string) (errc int) {
   427  	defer log.Trace(oldPath, "newPath=%q", newPath)("errc=%d", &errc)
   428  	return translateError(fsys.VFS.Rename(oldPath, newPath))
   429  }
   430  
   431  // Utimens changes the access and modification times of a file.
   432  func (fsys *FS) Utimens(path string, tmsp []fuse.Timespec) (errc int) {
   433  	defer log.Trace(path, "tmsp=%+v", tmsp)("errc=%d", &errc)
   434  	node, errc := fsys.lookupNode(path)
   435  	if errc != 0 {
   436  		return errc
   437  	}
   438  	var t time.Time
   439  	if tmsp == nil || len(tmsp) < 2 {
   440  		t = time.Now()
   441  	} else {
   442  		t = tmsp[1].Time()
   443  	}
   444  	return translateError(node.SetModTime(t))
   445  }
   446  
   447  // Mknod creates a file node.
   448  func (fsys *FS) Mknod(path string, mode uint32, dev uint64) (errc int) {
   449  	defer log.Trace(path, "mode=0x%X, dev=0x%X", mode, dev)("errc=%d", &errc)
   450  	return -fuse.ENOSYS
   451  }
   452  
   453  // Fsync synchronizes file contents.
   454  func (fsys *FS) Fsync(path string, datasync bool, fh uint64) (errc int) {
   455  	defer log.Trace(path, "datasync=%v, fh=0x%X", datasync, fh)("errc=%d", &errc)
   456  	// This is a no-op for rclone
   457  	return 0
   458  }
   459  
   460  // Link creates a hard link to a file.
   461  func (fsys *FS) Link(oldpath string, newpath string) (errc int) {
   462  	defer log.Trace(oldpath, "newpath=%q", newpath)("errc=%d", &errc)
   463  	return -fuse.ENOSYS
   464  }
   465  
   466  // Symlink creates a symbolic link.
   467  func (fsys *FS) Symlink(target string, newpath string) (errc int) {
   468  	defer log.Trace(target, "newpath=%q", newpath)("errc=%d", &errc)
   469  	return -fuse.ENOSYS
   470  }
   471  
   472  // Readlink reads the target of a symbolic link.
   473  func (fsys *FS) Readlink(path string) (errc int, linkPath string) {
   474  	defer log.Trace(path, "")("linkPath=%q, errc=%d", &linkPath, &errc)
   475  	return -fuse.ENOSYS, ""
   476  }
   477  
   478  // Chmod changes the permission bits of a file.
   479  func (fsys *FS) Chmod(path string, mode uint32) (errc int) {
   480  	defer log.Trace(path, "mode=0%o", mode)("errc=%d", &errc)
   481  	// This is a no-op for rclone
   482  	return 0
   483  }
   484  
   485  // Chown changes the owner and group of a file.
   486  func (fsys *FS) Chown(path string, uid uint32, gid uint32) (errc int) {
   487  	defer log.Trace(path, "uid=%d, gid=%d", uid, gid)("errc=%d", &errc)
   488  	// This is a no-op for rclone
   489  	return 0
   490  }
   491  
   492  // Access checks file access permissions.
   493  func (fsys *FS) Access(path string, mask uint32) (errc int) {
   494  	defer log.Trace(path, "mask=0%o", mask)("errc=%d", &errc)
   495  	// This is a no-op for rclone
   496  	return 0
   497  }
   498  
   499  // Fsyncdir synchronizes directory contents.
   500  func (fsys *FS) Fsyncdir(path string, datasync bool, fh uint64) (errc int) {
   501  	defer log.Trace(path, "datasync=%v, fh=0x%X", datasync, fh)("errc=%d", &errc)
   502  	// This is a no-op for rclone
   503  	return 0
   504  }
   505  
   506  // Setxattr sets extended attributes.
   507  func (fsys *FS) Setxattr(path string, name string, value []byte, flags int) (errc int) {
   508  	return -fuse.ENOSYS
   509  }
   510  
   511  // Getxattr gets extended attributes.
   512  func (fsys *FS) Getxattr(path string, name string) (errc int, value []byte) {
   513  	return -fuse.ENOSYS, nil
   514  }
   515  
   516  // Removexattr removes extended attributes.
   517  func (fsys *FS) Removexattr(path string, name string) (errc int) {
   518  	return -fuse.ENOSYS
   519  }
   520  
   521  // Listxattr lists extended attributes.
   522  func (fsys *FS) Listxattr(path string, fill func(name string) bool) (errc int) {
   523  	return -fuse.ENOSYS
   524  }
   525  
   526  // Translate errors from mountlib
   527  func translateError(err error) (errc int) {
   528  	if err == nil {
   529  		return 0
   530  	}
   531  	switch errors.Cause(err) {
   532  	case vfs.OK:
   533  		return 0
   534  	case vfs.ENOENT:
   535  		return -fuse.ENOENT
   536  	case vfs.EEXIST:
   537  		return -fuse.EEXIST
   538  	case vfs.EPERM:
   539  		return -fuse.EPERM
   540  	case vfs.ECLOSED:
   541  		return -fuse.EBADF
   542  	case vfs.ENOTEMPTY:
   543  		return -fuse.ENOTEMPTY
   544  	case vfs.ESPIPE:
   545  		return -fuse.ESPIPE
   546  	case vfs.EBADF:
   547  		return -fuse.EBADF
   548  	case vfs.EROFS:
   549  		return -fuse.EROFS
   550  	case vfs.ENOSYS:
   551  		return -fuse.ENOSYS
   552  	case vfs.EINVAL:
   553  		return -fuse.EINVAL
   554  	}
   555  	fs.Errorf(nil, "IO error: %v", err)
   556  	return -fuse.EIO
   557  }
   558  
   559  // Translate Open Flags from FUSE to os (as used in the vfs layer)
   560  func translateOpenFlags(inFlags int) (outFlags int) {
   561  	switch inFlags & fuse.O_ACCMODE {
   562  	case fuse.O_RDONLY:
   563  		outFlags = os.O_RDONLY
   564  	case fuse.O_WRONLY:
   565  		outFlags = os.O_WRONLY
   566  	case fuse.O_RDWR:
   567  		outFlags = os.O_RDWR
   568  	}
   569  	if inFlags&fuse.O_APPEND != 0 {
   570  		outFlags |= os.O_APPEND
   571  	}
   572  	if inFlags&fuse.O_CREAT != 0 {
   573  		outFlags |= os.O_CREATE
   574  	}
   575  	if inFlags&fuse.O_EXCL != 0 {
   576  		outFlags |= os.O_EXCL
   577  	}
   578  	if inFlags&fuse.O_TRUNC != 0 {
   579  		outFlags |= os.O_TRUNC
   580  	}
   581  	// NB O_SYNC isn't defined by fuse
   582  	return outFlags
   583  }