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

     1  // FUSE main Fs
     2  
     3  // +build linux darwin freebsd
     4  
     5  package mount
     6  
     7  import (
     8  	"context"
     9  	"syscall"
    10  
    11  	"bazil.org/fuse"
    12  	fusefs "bazil.org/fuse/fs"
    13  	"github.com/ncw/rclone/cmd/mountlib"
    14  	"github.com/ncw/rclone/fs"
    15  	"github.com/ncw/rclone/fs/log"
    16  	"github.com/ncw/rclone/vfs"
    17  	"github.com/ncw/rclone/vfs/vfsflags"
    18  	"github.com/pkg/errors"
    19  )
    20  
    21  // FS represents the top level filing system
    22  type FS struct {
    23  	*vfs.VFS
    24  	f fs.Fs
    25  }
    26  
    27  // Check interface satisfied
    28  var _ fusefs.FS = (*FS)(nil)
    29  
    30  // NewFS makes a new FS
    31  func NewFS(f fs.Fs) *FS {
    32  	fsys := &FS{
    33  		VFS: vfs.New(f, &vfsflags.Opt),
    34  		f:   f,
    35  	}
    36  	return fsys
    37  }
    38  
    39  // Root returns the root node
    40  func (f *FS) Root() (node fusefs.Node, err error) {
    41  	defer log.Trace("", "")("node=%+v, err=%v", &node, &err)
    42  	root, err := f.VFS.Root()
    43  	if err != nil {
    44  		return nil, translateError(err)
    45  	}
    46  	return &Dir{root}, nil
    47  }
    48  
    49  // Check interface satisfied
    50  var _ fusefs.FSStatfser = (*FS)(nil)
    51  
    52  // Statfs is called to obtain file system metadata.
    53  // It should write that data to resp.
    54  func (f *FS) Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.StatfsResponse) (err error) {
    55  	defer log.Trace("", "")("stat=%+v, err=%v", resp, &err)
    56  	const blockSize = 4096
    57  	const fsBlocks = (1 << 50) / blockSize
    58  	resp.Blocks = fsBlocks  // Total data blocks in file system.
    59  	resp.Bfree = fsBlocks   // Free blocks in file system.
    60  	resp.Bavail = fsBlocks  // Free blocks in file system if you're not root.
    61  	resp.Files = 1E9        // Total files in file system.
    62  	resp.Ffree = 1E9        // Free files in file system.
    63  	resp.Bsize = blockSize  // Block size
    64  	resp.Namelen = 255      // Maximum file name length?
    65  	resp.Frsize = blockSize // Fragment size, smallest addressable data size in the file system.
    66  	total, used, free := f.VFS.Statfs()
    67  	if total >= 0 {
    68  		resp.Blocks = uint64(total) / blockSize
    69  	}
    70  	if used >= 0 {
    71  		resp.Bfree = resp.Blocks - uint64(used)/blockSize
    72  	}
    73  	if free >= 0 {
    74  		resp.Bavail = uint64(free) / blockSize
    75  	}
    76  	mountlib.ClipBlocks(&resp.Blocks)
    77  	mountlib.ClipBlocks(&resp.Bfree)
    78  	mountlib.ClipBlocks(&resp.Bavail)
    79  	return nil
    80  }
    81  
    82  // Translate errors from mountlib
    83  func translateError(err error) error {
    84  	if err == nil {
    85  		return nil
    86  	}
    87  	switch errors.Cause(err) {
    88  	case vfs.OK:
    89  		return nil
    90  	case vfs.ENOENT:
    91  		return fuse.ENOENT
    92  	case vfs.EEXIST:
    93  		return fuse.EEXIST
    94  	case vfs.EPERM:
    95  		return fuse.EPERM
    96  	case vfs.ECLOSED:
    97  		return fuse.Errno(syscall.EBADF)
    98  	case vfs.ENOTEMPTY:
    99  		return fuse.Errno(syscall.ENOTEMPTY)
   100  	case vfs.ESPIPE:
   101  		return fuse.Errno(syscall.ESPIPE)
   102  	case vfs.EBADF:
   103  		return fuse.Errno(syscall.EBADF)
   104  	case vfs.EROFS:
   105  		return fuse.Errno(syscall.EROFS)
   106  	case vfs.ENOSYS:
   107  		return fuse.ENOSYS
   108  	case vfs.EINVAL:
   109  		return fuse.Errno(syscall.EINVAL)
   110  	}
   111  	return err
   112  }