github.com/rclone/rclone@v1.66.1-0.20240517100346-7b89735ae726/cmd/mount/fs.go (about)

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