mirror of
https://github.com/rclone/rclone.git
synced 2024-12-30 08:53:40 +08:00
142 lines
3.2 KiB
Go
142 lines
3.2 KiB
Go
// FUSE main Fs
|
|
|
|
//go:build linux || (darwin && amd64)
|
|
|
|
package mount2
|
|
|
|
import (
|
|
"os"
|
|
"syscall"
|
|
"time"
|
|
|
|
"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)
|
|
}
|
|
|
|
// 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(time.Duration(f.opt.AttrTimeout))
|
|
}
|
|
|
|
// fill in EntryOut from node
|
|
func (f *FS) setEntryOut(node vfs.Node, out *fuse.EntryOut) {
|
|
setAttr(node, &out.Attr)
|
|
out.SetEntryTimeout(time.Duration(f.opt.AttrTimeout))
|
|
out.SetAttrTimeout(time.Duration(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
|
|
case vfs.ELOOP:
|
|
return syscall.ELOOP
|
|
}
|
|
fs.Errorf(nil, "IO error: %v", err)
|
|
return syscall.EIO
|
|
}
|