mirror of
https://github.com/rclone/rclone.git
synced 2025-01-03 12:59:32 +01:00
19c6081de2
We enable symlink support using the --links command line switch. When symlink support is enabled, the mount backends will translate the name of the vfs symlinks files (truncating their rclonelink suffix). Also, operations like rename, symlink etc does not needs the rclonelink suffix, it is handled internally to pass it to the underlying low level VFS. When symlink support is disabled, Symlink and Readlink functions will transparently manage ".rclonelink" files as regular files. Fixes #2975
159 lines
3.6 KiB
Go
159 lines
3.6 KiB
Go
// FUSE main Fs
|
|
|
|
//go:build linux || (darwin && amd64)
|
|
// +build linux darwin,amd64
|
|
|
|
package mount2
|
|
|
|
import (
|
|
"os"
|
|
"syscall"
|
|
|
|
"github.com/hanwen/go-fuse/v2/fuse"
|
|
"github.com/rclone/rclone/cmd/mountlib"
|
|
"github.com/rclone/rclone/fs"
|
|
"github.com/rclone/rclone/fs/fserrors"
|
|
"github.com/rclone/rclone/fs/log"
|
|
"github.com/rclone/rclone/vfs"
|
|
)
|
|
|
|
// FS represents the top level filing system
|
|
type FS struct {
|
|
VFS *vfs.VFS
|
|
f fs.Fs
|
|
opt *mountlib.Options
|
|
}
|
|
|
|
// NewFS creates a pathfs.FileSystem from the fs.Fs passed in
|
|
func NewFS(VFS *vfs.VFS, opt *mountlib.Options) *FS {
|
|
fsys := &FS{
|
|
VFS: VFS,
|
|
f: VFS.Fs(),
|
|
opt: opt,
|
|
}
|
|
return fsys
|
|
}
|
|
|
|
// Root returns the root node
|
|
func (f *FS) Root() (node *Node, err error) {
|
|
defer log.Trace("", "")("node=%+v, err=%v", &node, &err)
|
|
root, err := f.VFS.Root()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return newNode(f, root), nil
|
|
}
|
|
|
|
// SetDebug if called, provide debug output through the log package.
|
|
func (f *FS) SetDebug(debug bool) {
|
|
fs.Debugf(f.f, "SetDebug %v", debug)
|
|
}
|
|
|
|
// get the Mode from a vfs Node
|
|
func getMode(node os.FileInfo) uint32 {
|
|
vfsMode := node.Mode()
|
|
Mode := vfsMode.Perm()
|
|
if vfsMode&os.ModeDir != 0 {
|
|
Mode |= fuse.S_IFDIR
|
|
} else if vfsMode&os.ModeSymlink != 0 {
|
|
Mode |= fuse.S_IFLNK
|
|
} else if vfsMode&os.ModeNamedPipe != 0 {
|
|
Mode |= fuse.S_IFIFO
|
|
} else {
|
|
Mode |= fuse.S_IFREG
|
|
}
|
|
return uint32(Mode)
|
|
}
|
|
|
|
// convert fuse mode to os.FileMode
|
|
// func getFileMode(mode uint32) os.FileMode {
|
|
// osMode := os.FileMode(0)
|
|
// if mode&fuse.S_IFDIR != 0 {
|
|
// mode ^= fuse.S_IFDIR
|
|
// osMode |= os.ModeDir
|
|
// } else if mode&fuse.S_IFREG != 0 {
|
|
// mode ^= fuse.S_IFREG
|
|
// } else if mode&fuse.S_IFLNK != 0 {
|
|
// mode ^= fuse.S_IFLNK
|
|
// osMode |= os.ModeSymlink
|
|
// } else if mode&fuse.S_IFIFO != 0 {
|
|
// mode ^= fuse.S_IFIFO
|
|
// osMode |= os.ModeNamedPipe
|
|
// }
|
|
// osMode |= os.FileMode(mode)
|
|
// return osMode
|
|
// }
|
|
|
|
// fill in attr from node
|
|
func setAttr(node vfs.Node, attr *fuse.Attr) {
|
|
Size := uint64(node.Size())
|
|
const BlockSize = 512
|
|
Blocks := (Size + BlockSize - 1) / BlockSize
|
|
modTime := node.ModTime()
|
|
// set attributes
|
|
vfs := node.VFS()
|
|
attr.Owner.Gid = vfs.Opt.GID
|
|
attr.Owner.Uid = vfs.Opt.UID
|
|
attr.Mode = getMode(node)
|
|
attr.Size = Size
|
|
attr.Nlink = 1
|
|
attr.Blocks = Blocks
|
|
// attr.Blksize = BlockSize // not supported in freebsd/darwin, defaults to 4k if not set
|
|
s := uint64(modTime.Unix())
|
|
ns := uint32(modTime.Nanosecond())
|
|
attr.Atime = s
|
|
attr.Atimensec = ns
|
|
attr.Mtime = s
|
|
attr.Mtimensec = ns
|
|
attr.Ctime = s
|
|
attr.Ctimensec = ns
|
|
//attr.Rdev
|
|
}
|
|
|
|
// fill in AttrOut from node
|
|
func (f *FS) setAttrOut(node vfs.Node, out *fuse.AttrOut) {
|
|
setAttr(node, &out.Attr)
|
|
out.SetTimeout(f.opt.AttrTimeout)
|
|
}
|
|
|
|
// fill in EntryOut from node
|
|
func (f *FS) setEntryOut(node vfs.Node, out *fuse.EntryOut) {
|
|
setAttr(node, &out.Attr)
|
|
out.SetEntryTimeout(f.opt.AttrTimeout)
|
|
out.SetAttrTimeout(f.opt.AttrTimeout)
|
|
}
|
|
|
|
// Translate errors from mountlib into Syscall error numbers
|
|
func translateError(err error) syscall.Errno {
|
|
if err == nil {
|
|
return 0
|
|
}
|
|
_, uErr := fserrors.Cause(err)
|
|
switch uErr {
|
|
case vfs.OK:
|
|
return 0
|
|
case vfs.ENOENT, fs.ErrorDirNotFound, fs.ErrorObjectNotFound:
|
|
return syscall.ENOENT
|
|
case vfs.EEXIST, fs.ErrorDirExists:
|
|
return syscall.EEXIST
|
|
case vfs.EPERM, fs.ErrorPermissionDenied:
|
|
return syscall.EPERM
|
|
case vfs.ECLOSED:
|
|
return syscall.EBADF
|
|
case vfs.ENOTEMPTY:
|
|
return syscall.ENOTEMPTY
|
|
case vfs.ESPIPE:
|
|
return syscall.ESPIPE
|
|
case vfs.EBADF:
|
|
return syscall.EBADF
|
|
case vfs.EROFS:
|
|
return syscall.EROFS
|
|
case vfs.ENOSYS, fs.ErrorNotImplemented:
|
|
return syscall.ENOSYS
|
|
case vfs.EINVAL:
|
|
return syscall.EINVAL
|
|
}
|
|
fs.Errorf(nil, "IO error: %v", err)
|
|
return syscall.EIO
|
|
}
|