mirror of
https://github.com/rclone/rclone.git
synced 2024-11-25 06:19:00 +08:00
vfs: convert vfs options to new style
This also - move in use options (Opt) from vfsflags to vfscommon - change os.FileMode to vfscommon.FileMode in parameters - rework vfscommon.FileMode and add tests
This commit is contained in:
parent
fc1d8dafd5
commit
a28287e96d
14
backend/cache/cache_internal_test.go
vendored
14
backend/cache/cache_internal_test.go
vendored
|
@ -33,7 +33,7 @@ import (
|
||||||
"github.com/rclone/rclone/fstest"
|
"github.com/rclone/rclone/fstest"
|
||||||
"github.com/rclone/rclone/fstest/testy"
|
"github.com/rclone/rclone/fstest/testy"
|
||||||
"github.com/rclone/rclone/lib/random"
|
"github.com/rclone/rclone/lib/random"
|
||||||
"github.com/rclone/rclone/vfs/vfsflags"
|
"github.com/rclone/rclone/vfs/vfscommon"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -123,10 +123,10 @@ func TestInternalListRootAndInnerRemotes(t *testing.T) {
|
||||||
|
|
||||||
/* TODO: is this testing something?
|
/* TODO: is this testing something?
|
||||||
func TestInternalVfsCache(t *testing.T) {
|
func TestInternalVfsCache(t *testing.T) {
|
||||||
vfsflags.Opt.DirCacheTime = time.Second * 30
|
vfscommon.Opt.DirCacheTime = time.Second * 30
|
||||||
testSize := int64(524288000)
|
testSize := int64(524288000)
|
||||||
|
|
||||||
vfsflags.Opt.CacheMode = vfs.CacheModeWrites
|
vfscommon.Opt.CacheMode = vfs.CacheModeWrites
|
||||||
id := "tiuufo"
|
id := "tiuufo"
|
||||||
rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, true, true, nil, map[string]string{"writes": "true", "info_age": "1h"})
|
rootFs, boltDb := runInstance.newCacheFs(t, remoteName, id, true, true, nil, map[string]string{"writes": "true", "info_age": "1h"})
|
||||||
defer runInstance.cleanupFs(t, rootFs, boltDb)
|
defer runInstance.cleanupFs(t, rootFs, boltDb)
|
||||||
|
@ -338,7 +338,7 @@ func TestInternalCachedUpdatedContentMatches(t *testing.T) {
|
||||||
|
|
||||||
func TestInternalWrappedWrittenContentMatches(t *testing.T) {
|
func TestInternalWrappedWrittenContentMatches(t *testing.T) {
|
||||||
id := fmt.Sprintf("tiwwcm%v", time.Now().Unix())
|
id := fmt.Sprintf("tiwwcm%v", time.Now().Unix())
|
||||||
vfsflags.Opt.DirCacheTime = fs.Duration(time.Second)
|
vfscommon.Opt.DirCacheTime = fs.Duration(time.Second)
|
||||||
rootFs, _ := runInstance.newCacheFs(t, remoteName, id, true, true, nil)
|
rootFs, _ := runInstance.newCacheFs(t, remoteName, id, true, true, nil)
|
||||||
if runInstance.rootIsCrypt {
|
if runInstance.rootIsCrypt {
|
||||||
t.Skip("test skipped with crypt remote")
|
t.Skip("test skipped with crypt remote")
|
||||||
|
@ -368,7 +368,7 @@ func TestInternalWrappedWrittenContentMatches(t *testing.T) {
|
||||||
|
|
||||||
func TestInternalLargeWrittenContentMatches(t *testing.T) {
|
func TestInternalLargeWrittenContentMatches(t *testing.T) {
|
||||||
id := fmt.Sprintf("tilwcm%v", time.Now().Unix())
|
id := fmt.Sprintf("tilwcm%v", time.Now().Unix())
|
||||||
vfsflags.Opt.DirCacheTime = fs.Duration(time.Second)
|
vfscommon.Opt.DirCacheTime = fs.Duration(time.Second)
|
||||||
rootFs, _ := runInstance.newCacheFs(t, remoteName, id, true, true, nil)
|
rootFs, _ := runInstance.newCacheFs(t, remoteName, id, true, true, nil)
|
||||||
if runInstance.rootIsCrypt {
|
if runInstance.rootIsCrypt {
|
||||||
t.Skip("test skipped with crypt remote")
|
t.Skip("test skipped with crypt remote")
|
||||||
|
@ -708,7 +708,7 @@ func TestInternalMaxChunkSizeRespected(t *testing.T) {
|
||||||
|
|
||||||
func TestInternalExpiredEntriesRemoved(t *testing.T) {
|
func TestInternalExpiredEntriesRemoved(t *testing.T) {
|
||||||
id := fmt.Sprintf("tieer%v", time.Now().Unix())
|
id := fmt.Sprintf("tieer%v", time.Now().Unix())
|
||||||
vfsflags.Opt.DirCacheTime = fs.Duration(time.Second * 4) // needs to be lower than the defined
|
vfscommon.Opt.DirCacheTime = fs.Duration(time.Second * 4) // needs to be lower than the defined
|
||||||
rootFs, _ := runInstance.newCacheFs(t, remoteName, id, true, true, nil)
|
rootFs, _ := runInstance.newCacheFs(t, remoteName, id, true, true, nil)
|
||||||
cfs, err := runInstance.getCacheFs(rootFs)
|
cfs, err := runInstance.getCacheFs(rootFs)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -743,7 +743,7 @@ func TestInternalExpiredEntriesRemoved(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInternalBug2117(t *testing.T) {
|
func TestInternalBug2117(t *testing.T) {
|
||||||
vfsflags.Opt.DirCacheTime = fs.Duration(time.Second * 10)
|
vfscommon.Opt.DirCacheTime = fs.Duration(time.Second * 10)
|
||||||
|
|
||||||
id := fmt.Sprintf("tib2117%v", time.Now().Unix())
|
id := fmt.Sprintf("tib2117%v", time.Now().Unix())
|
||||||
rootFs, _ := runInstance.newCacheFs(t, remoteName, id, false, true, map[string]string{"info_age": "72h", "chunk_clean_interval": "15m"})
|
rootFs, _ := runInstance.newCacheFs(t, remoteName, id, false, true, map[string]string{"info_age": "72h", "chunk_clean_interval": "15m"})
|
||||||
|
|
|
@ -33,7 +33,7 @@ func (d *Dir) Attr(ctx context.Context, a *fuse.Attr) (err error) {
|
||||||
a.Valid = time.Duration(d.fsys.opt.AttrTimeout)
|
a.Valid = time.Duration(d.fsys.opt.AttrTimeout)
|
||||||
a.Gid = d.VFS().Opt.GID
|
a.Gid = d.VFS().Opt.GID
|
||||||
a.Uid = d.VFS().Opt.UID
|
a.Uid = d.VFS().Opt.UID
|
||||||
a.Mode = os.ModeDir | d.VFS().Opt.DirPerms
|
a.Mode = os.ModeDir | os.FileMode(d.VFS().Opt.DirPerms)
|
||||||
modTime := d.ModTime()
|
modTime := d.ModTime()
|
||||||
a.Atime = modTime
|
a.Atime = modTime
|
||||||
a.Mtime = modTime
|
a.Mtime = modTime
|
||||||
|
|
|
@ -4,6 +4,7 @@ package mount
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"os"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ func (f *File) Attr(ctx context.Context, a *fuse.Attr) (err error) {
|
||||||
Blocks := (Size + 511) / 512
|
Blocks := (Size + 511) / 512
|
||||||
a.Gid = f.VFS().Opt.GID
|
a.Gid = f.VFS().Opt.GID
|
||||||
a.Uid = f.VFS().Opt.UID
|
a.Uid = f.VFS().Opt.UID
|
||||||
a.Mode = f.VFS().Opt.FilePerms
|
a.Mode = os.FileMode(f.VFS().Opt.FilePerms)
|
||||||
a.Size = Size
|
a.Size = Size
|
||||||
a.Atime = modTime
|
a.Atime = modTime
|
||||||
a.Mtime = modTime
|
a.Mtime = modTime
|
||||||
|
|
|
@ -228,7 +228,7 @@ func NewMountCommand(commandName string, hidden bool, mount MountFn) *cobra.Comm
|
||||||
defer cmd.StartStats()()
|
defer cmd.StartStats()()
|
||||||
}
|
}
|
||||||
|
|
||||||
mnt := NewMountPoint(mount, args[1], cmd.NewFsDir(args), &Opt, &vfsflags.Opt)
|
mnt := NewMountPoint(mount, args[1], cmd.NewFsDir(args), &Opt, &vfscommon.Opt)
|
||||||
mountDaemon, err := mnt.Mount()
|
mountDaemon, err := mnt.Mount()
|
||||||
|
|
||||||
// Wait for foreground mount, if any...
|
// Wait for foreground mount, if any...
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/rclone/rclone/fs"
|
"github.com/rclone/rclone/fs"
|
||||||
"github.com/rclone/rclone/fs/rc"
|
"github.com/rclone/rclone/fs/rc"
|
||||||
"github.com/rclone/rclone/vfs/vfsflags"
|
"github.com/rclone/rclone/vfs/vfscommon"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -85,7 +85,7 @@ func mountRc(ctx context.Context, in rc.Params) (out rc.Params, err error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
vfsOpt := vfsflags.Opt
|
vfsOpt := vfscommon.Opt
|
||||||
err = in.GetStructMissingOK("vfsOpt", &vfsOpt)
|
err = in.GetStructMissingOK("vfsOpt", &vfsOpt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/rclone/rclone/fs"
|
"github.com/rclone/rclone/fs"
|
||||||
"github.com/rclone/rclone/lib/systemd"
|
"github.com/rclone/rclone/lib/systemd"
|
||||||
"github.com/rclone/rclone/vfs"
|
"github.com/rclone/rclone/vfs"
|
||||||
|
"github.com/rclone/rclone/vfs/vfscommon"
|
||||||
"github.com/rclone/rclone/vfs/vfsflags"
|
"github.com/rclone/rclone/vfs/vfsflags"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
@ -134,7 +135,7 @@ func newServer(f fs.Fs, opt *dlnaflags.Options) (*server, error) {
|
||||||
waitChan: make(chan struct{}),
|
waitChan: make(chan struct{}),
|
||||||
httpListenAddr: opt.ListenAddr,
|
httpListenAddr: opt.ListenAddr,
|
||||||
f: f,
|
f: f,
|
||||||
vfs: vfs.New(f, &vfsflags.Opt),
|
vfs: vfs.New(f, &vfscommon.Opt),
|
||||||
}
|
}
|
||||||
|
|
||||||
s.services = map[string]UPnPService{
|
s.services = map[string]UPnPService{
|
||||||
|
|
|
@ -19,7 +19,6 @@ import (
|
||||||
"github.com/rclone/rclone/lib/atexit"
|
"github.com/rclone/rclone/lib/atexit"
|
||||||
"github.com/rclone/rclone/lib/file"
|
"github.com/rclone/rclone/lib/file"
|
||||||
"github.com/rclone/rclone/vfs/vfscommon"
|
"github.com/rclone/rclone/vfs/vfscommon"
|
||||||
"github.com/rclone/rclone/vfs/vfsflags"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Driver implements docker driver api
|
// Driver implements docker driver api
|
||||||
|
@ -55,7 +54,7 @@ func NewDriver(ctx context.Context, root string, mntOpt *mountlib.Options, vfsOp
|
||||||
mntOpt = &mountlib.Opt
|
mntOpt = &mountlib.Opt
|
||||||
}
|
}
|
||||||
if vfsOpt == nil {
|
if vfsOpt == nil {
|
||||||
vfsOpt = &vfsflags.Opt
|
vfsOpt = &vfscommon.Opt
|
||||||
}
|
}
|
||||||
drv := &Driver{
|
drv := &Driver{
|
||||||
root: root,
|
root: root,
|
||||||
|
|
|
@ -2,7 +2,6 @@ package docker
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/rclone/rclone/cmd/mountlib"
|
"github.com/rclone/rclone/cmd/mountlib"
|
||||||
|
@ -11,7 +10,6 @@ import (
|
||||||
"github.com/rclone/rclone/fs/fspath"
|
"github.com/rclone/rclone/fs/fspath"
|
||||||
"github.com/rclone/rclone/fs/rc"
|
"github.com/rclone/rclone/fs/rc"
|
||||||
"github.com/rclone/rclone/vfs/vfscommon"
|
"github.com/rclone/rclone/vfs/vfscommon"
|
||||||
"github.com/rclone/rclone/vfs/vfsflags"
|
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
@ -265,22 +263,13 @@ func getVFSOption(vfsOpt *vfscommon.Options, opt rc.Params, key string) (ok bool
|
||||||
case "read-only":
|
case "read-only":
|
||||||
vfsOpt.ReadOnly, err = opt.GetBool(key)
|
vfsOpt.ReadOnly, err = opt.GetBool(key)
|
||||||
case "dir-perms":
|
case "dir-perms":
|
||||||
perms := &vfsflags.FileMode{Mode: &vfsOpt.DirPerms}
|
err = getFVarP(&vfsOpt.DirPerms, opt, key)
|
||||||
err = getFVarP(perms, opt, key)
|
|
||||||
case "file-perms":
|
case "file-perms":
|
||||||
perms := &vfsflags.FileMode{Mode: &vfsOpt.FilePerms}
|
err = getFVarP(&vfsOpt.FilePerms, opt, key)
|
||||||
err = getFVarP(perms, opt, key)
|
|
||||||
|
|
||||||
// unprefixed unix-only vfs options
|
// unprefixed unix-only vfs options
|
||||||
case "umask":
|
case "umask":
|
||||||
// GetInt64 doesn't support the `0octal` umask syntax - parse locally
|
err = getFVarP(&vfsOpt.Umask, opt, key)
|
||||||
var strVal string
|
|
||||||
if strVal, err = opt.GetString(key); err == nil {
|
|
||||||
var longVal int64
|
|
||||||
if longVal, err = strconv.ParseInt(strVal, 0, 0); err == nil {
|
|
||||||
vfsOpt.Umask = int(longVal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "uid":
|
case "uid":
|
||||||
intVal, err = opt.GetInt64(key)
|
intVal, err = opt.GetInt64(key)
|
||||||
vfsOpt.UID = uint32(intVal)
|
vfsOpt.UID = uint32(intVal)
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/rclone/rclone/fs/log"
|
"github.com/rclone/rclone/fs/log"
|
||||||
"github.com/rclone/rclone/fs/rc"
|
"github.com/rclone/rclone/fs/rc"
|
||||||
"github.com/rclone/rclone/vfs"
|
"github.com/rclone/rclone/vfs"
|
||||||
|
"github.com/rclone/rclone/vfs/vfscommon"
|
||||||
"github.com/rclone/rclone/vfs/vfsflags"
|
"github.com/rclone/rclone/vfs/vfsflags"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
@ -157,7 +158,7 @@ func newServer(ctx context.Context, f fs.Fs, opt *Options) (*driver, error) {
|
||||||
d.proxy = proxy.New(ctx, &proxyflags.Opt)
|
d.proxy = proxy.New(ctx, &proxyflags.Opt)
|
||||||
d.userPass = make(map[string]string, 16)
|
d.userPass = make(map[string]string, 16)
|
||||||
} else {
|
} else {
|
||||||
d.globalVFS = vfs.New(f, &vfsflags.Opt)
|
d.globalVFS = vfs.New(f, &vfscommon.Opt)
|
||||||
}
|
}
|
||||||
d.useTLS = d.opt.TLSKey != ""
|
d.useTLS = d.opt.TLSKey != ""
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/rclone/rclone/lib/http/serve"
|
"github.com/rclone/rclone/lib/http/serve"
|
||||||
"github.com/rclone/rclone/lib/systemd"
|
"github.com/rclone/rclone/lib/systemd"
|
||||||
"github.com/rclone/rclone/vfs"
|
"github.com/rclone/rclone/vfs"
|
||||||
|
"github.com/rclone/rclone/vfs/vfscommon"
|
||||||
"github.com/rclone/rclone/vfs/vfsflags"
|
"github.com/rclone/rclone/vfs/vfsflags"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
@ -148,7 +149,7 @@ func run(ctx context.Context, f fs.Fs, opt Options) (s *HTTP, err error) {
|
||||||
// override auth
|
// override auth
|
||||||
s.opt.Auth.CustomAuthFn = s.auth
|
s.opt.Auth.CustomAuthFn = s.auth
|
||||||
} else {
|
} else {
|
||||||
s._vfs = vfs.New(f, &vfsflags.Opt)
|
s._vfs = vfs.New(f, &vfscommon.Opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.server, err = libhttp.NewServer(ctx,
|
s.server, err = libhttp.NewServer(ctx,
|
||||||
|
@ -215,7 +216,7 @@ func (s *HTTP) serveDir(w http.ResponseWriter, r *http.Request, dirRemote string
|
||||||
// Make the entries for display
|
// Make the entries for display
|
||||||
directory := serve.NewDirectory(dirRemote, s.server.HTMLTemplate())
|
directory := serve.NewDirectory(dirRemote, s.server.HTMLTemplate())
|
||||||
for _, node := range dirEntries {
|
for _, node := range dirEntries {
|
||||||
if vfsflags.Opt.NoModTime {
|
if vfscommon.Opt.NoModTime {
|
||||||
directory.AddHTMLEntry(node.Path(), node.IsDir(), node.Size(), time.Time{})
|
directory.AddHTMLEntry(node.Path(), node.IsDir(), node.Size(), time.Time{})
|
||||||
} else {
|
} else {
|
||||||
directory.AddHTMLEntry(node.Path(), node.IsDir(), node.Size(), node.ModTime().UTC())
|
directory.AddHTMLEntry(node.Path(), node.IsDir(), node.Size(), node.ModTime().UTC())
|
||||||
|
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"github.com/rclone/rclone/fs/config/flags"
|
"github.com/rclone/rclone/fs/config/flags"
|
||||||
"github.com/rclone/rclone/fs/rc"
|
"github.com/rclone/rclone/fs/rc"
|
||||||
"github.com/rclone/rclone/vfs"
|
"github.com/rclone/rclone/vfs"
|
||||||
|
"github.com/rclone/rclone/vfs/vfscommon"
|
||||||
"github.com/rclone/rclone/vfs/vfsflags"
|
"github.com/rclone/rclone/vfs/vfsflags"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
|
@ -48,7 +49,7 @@ func Run(command *cobra.Command, args []string) {
|
||||||
cmd.CheckArgs(1, 1, command, args)
|
cmd.CheckArgs(1, 1, command, args)
|
||||||
f = cmd.NewFsSrc(args)
|
f = cmd.NewFsSrc(args)
|
||||||
cmd.Run(false, true, command, func() error {
|
cmd.Run(false, true, command, func() error {
|
||||||
s, err := NewServer(context.Background(), vfs.New(f, &vfsflags.Opt), &opt)
|
s, err := NewServer(context.Background(), vfs.New(f, &vfscommon.Opt), &opt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
"github.com/rclone/rclone/fs/config/obscure"
|
"github.com/rclone/rclone/fs/config/obscure"
|
||||||
libcache "github.com/rclone/rclone/lib/cache"
|
libcache "github.com/rclone/rclone/lib/cache"
|
||||||
"github.com/rclone/rclone/vfs"
|
"github.com/rclone/rclone/vfs"
|
||||||
"github.com/rclone/rclone/vfs/vfsflags"
|
"github.com/rclone/rclone/vfs/vfscommon"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Help contains text describing how to use the proxy
|
// Help contains text describing how to use the proxy
|
||||||
|
@ -242,7 +242,7 @@ func (p *Proxy) call(user, auth string, isPublicKey bool) (value interface{}, er
|
||||||
// need to in memory. An attacker would find it easier to go
|
// need to in memory. An attacker would find it easier to go
|
||||||
// after the unencrypted password in memory most likely.
|
// after the unencrypted password in memory most likely.
|
||||||
entry := cacheEntry{
|
entry := cacheEntry{
|
||||||
vfs: vfs.New(f, &vfsflags.Opt),
|
vfs: vfs.New(f, &vfscommon.Opt),
|
||||||
pwHash: sha256.Sum256([]byte(auth)),
|
pwHash: sha256.Sum256([]byte(auth)),
|
||||||
}
|
}
|
||||||
return entry, true, nil
|
return entry, true, nil
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
"github.com/rclone/rclone/fs/hash"
|
"github.com/rclone/rclone/fs/hash"
|
||||||
httplib "github.com/rclone/rclone/lib/http"
|
httplib "github.com/rclone/rclone/lib/http"
|
||||||
"github.com/rclone/rclone/vfs"
|
"github.com/rclone/rclone/vfs"
|
||||||
"github.com/rclone/rclone/vfs/vfsflags"
|
"github.com/rclone/rclone/vfs/vfscommon"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options contains options for the http Server
|
// Options contains options for the http Server
|
||||||
|
@ -42,7 +42,7 @@ func newServer(ctx context.Context, f fs.Fs, opt *Options) (s *Server, err error
|
||||||
w := &Server{
|
w := &Server{
|
||||||
f: f,
|
f: f,
|
||||||
ctx: ctx,
|
ctx: ctx,
|
||||||
vfs: vfs.New(f, &vfsflags.Opt),
|
vfs: vfs.New(f, &vfscommon.Opt),
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(opt.authPair) == 0 {
|
if len(opt.authPair) == 0 {
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
"github.com/rclone/rclone/fs/hash"
|
"github.com/rclone/rclone/fs/hash"
|
||||||
"github.com/rclone/rclone/lib/terminal"
|
"github.com/rclone/rclone/lib/terminal"
|
||||||
"github.com/rclone/rclone/vfs"
|
"github.com/rclone/rclone/vfs"
|
||||||
"github.com/rclone/rclone/vfs/vfsflags"
|
"github.com/rclone/rclone/vfs/vfscommon"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -307,7 +307,7 @@ func serveStdio(f fs.Fs) error {
|
||||||
stdin: os.Stdin,
|
stdin: os.Stdin,
|
||||||
stdout: os.Stdout,
|
stdout: os.Stdout,
|
||||||
}
|
}
|
||||||
handlers := newVFSHandler(vfs.New(f, &vfsflags.Opt))
|
handlers := newVFSHandler(vfs.New(f, &vfscommon.Opt))
|
||||||
return serveChannel(sshChannel, handlers, "stdio")
|
return serveChannel(sshChannel, handlers, "stdio")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ import (
|
||||||
"github.com/rclone/rclone/lib/env"
|
"github.com/rclone/rclone/lib/env"
|
||||||
"github.com/rclone/rclone/lib/file"
|
"github.com/rclone/rclone/lib/file"
|
||||||
"github.com/rclone/rclone/vfs"
|
"github.com/rclone/rclone/vfs"
|
||||||
"github.com/rclone/rclone/vfs/vfsflags"
|
"github.com/rclone/rclone/vfs/vfscommon"
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ func newServer(ctx context.Context, f fs.Fs, opt *Options) *server {
|
||||||
if proxyflags.Opt.AuthProxy != "" {
|
if proxyflags.Opt.AuthProxy != "" {
|
||||||
s.proxy = proxy.New(ctx, &proxyflags.Opt)
|
s.proxy = proxy.New(ctx, &proxyflags.Opt)
|
||||||
} else {
|
} else {
|
||||||
s.vfs = vfs.New(f, &vfsflags.Opt)
|
s.vfs = vfs.New(f, &vfscommon.Opt)
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
"github.com/rclone/rclone/lib/http/serve"
|
"github.com/rclone/rclone/lib/http/serve"
|
||||||
"github.com/rclone/rclone/lib/systemd"
|
"github.com/rclone/rclone/lib/systemd"
|
||||||
"github.com/rclone/rclone/vfs"
|
"github.com/rclone/rclone/vfs"
|
||||||
|
"github.com/rclone/rclone/vfs/vfscommon"
|
||||||
"github.com/rclone/rclone/vfs/vfsflags"
|
"github.com/rclone/rclone/vfs/vfsflags"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"golang.org/x/net/webdav"
|
"golang.org/x/net/webdav"
|
||||||
|
@ -193,7 +194,7 @@ func newWebDAV(ctx context.Context, f fs.Fs, opt *Options) (w *WebDAV, err error
|
||||||
// override auth
|
// override auth
|
||||||
w.opt.Auth.CustomAuthFn = w.auth
|
w.opt.Auth.CustomAuthFn = w.auth
|
||||||
} else {
|
} else {
|
||||||
w._vfs = vfs.New(f, &vfsflags.Opt)
|
w._vfs = vfs.New(f, &vfscommon.Opt)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Server, err = libhttp.NewServer(ctx,
|
w.Server, err = libhttp.NewServer(ctx,
|
||||||
|
@ -365,7 +366,7 @@ func (w *WebDAV) serveDir(rw http.ResponseWriter, r *http.Request, dirRemote str
|
||||||
// Make the entries for display
|
// Make the entries for display
|
||||||
directory := serve.NewDirectory(dirRemote, w.Server.HTMLTemplate())
|
directory := serve.NewDirectory(dirRemote, w.Server.HTMLTemplate())
|
||||||
for _, node := range dirEntries {
|
for _, node := range dirEntries {
|
||||||
if vfsflags.Opt.NoModTime {
|
if vfscommon.Opt.NoModTime {
|
||||||
directory.AddHTMLEntry(node.Path(), node.IsDir(), node.Size(), time.Time{})
|
directory.AddHTMLEntry(node.Path(), node.IsDir(), node.Size(), time.Time{})
|
||||||
} else {
|
} else {
|
||||||
directory.AddHTMLEntry(node.Path(), node.IsDir(), node.Size(), node.ModTime().UTC())
|
directory.AddHTMLEntry(node.Path(), node.IsDir(), node.Size(), node.ModTime().UTC())
|
||||||
|
|
|
@ -157,7 +157,7 @@ func (d *Dir) IsDir() bool {
|
||||||
|
|
||||||
// Mode bits of the directory - satisfies Node interface
|
// Mode bits of the directory - satisfies Node interface
|
||||||
func (d *Dir) Mode() (mode os.FileMode) {
|
func (d *Dir) Mode() (mode os.FileMode) {
|
||||||
return d.vfs.Opt.DirPerms
|
return os.FileMode(d.vfs.Opt.DirPerms)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name (base) of the directory - satisfies Node interface
|
// Name (base) of the directory - satisfies Node interface
|
||||||
|
|
|
@ -43,7 +43,7 @@ func TestDirMethods(t *testing.T) {
|
||||||
assert.Equal(t, false, dir.IsFile())
|
assert.Equal(t, false, dir.IsFile())
|
||||||
|
|
||||||
// Mode
|
// Mode
|
||||||
assert.Equal(t, vfs.Opt.DirPerms, dir.Mode())
|
assert.Equal(t, os.FileMode(vfs.Opt.DirPerms), dir.Mode())
|
||||||
|
|
||||||
// Name
|
// Name
|
||||||
assert.Equal(t, "dir", dir.Name())
|
assert.Equal(t, "dir", dir.Name())
|
||||||
|
|
|
@ -94,7 +94,7 @@ func (f *File) IsDir() bool {
|
||||||
func (f *File) Mode() (mode os.FileMode) {
|
func (f *File) Mode() (mode os.FileMode) {
|
||||||
f.mu.RLock()
|
f.mu.RLock()
|
||||||
defer f.mu.RUnlock()
|
defer f.mu.RUnlock()
|
||||||
mode = f.d.vfs.Opt.FilePerms
|
mode = os.FileMode(f.d.vfs.Opt.FilePerms)
|
||||||
if f.appendMode {
|
if f.appendMode {
|
||||||
mode |= os.ModeAppend
|
mode |= os.ModeAppend
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func fileCreate(t *testing.T, mode vfscommon.CacheMode) (r *fstest.Run, vfs *VFS, fh *File, item fstest.Item) {
|
func fileCreate(t *testing.T, mode vfscommon.CacheMode) (r *fstest.Run, vfs *VFS, fh *File, item fstest.Item) {
|
||||||
opt := vfscommon.DefaultOpt
|
opt := vfscommon.Opt
|
||||||
opt.CacheMode = mode
|
opt.CacheMode = mode
|
||||||
opt.WriteBack = writeBackDelay
|
opt.WriteBack = writeBackDelay
|
||||||
r, vfs = newTestVFSOpt(t, &opt)
|
r, vfs = newTestVFSOpt(t, &opt)
|
||||||
|
@ -48,7 +48,7 @@ func TestFileMethods(t *testing.T) {
|
||||||
assert.Equal(t, true, file.IsFile())
|
assert.Equal(t, true, file.IsFile())
|
||||||
|
|
||||||
// Mode
|
// Mode
|
||||||
assert.Equal(t, vfs.Opt.FilePerms, file.Mode())
|
assert.Equal(t, os.FileMode(vfs.Opt.FilePerms), file.Mode())
|
||||||
|
|
||||||
// Name
|
// Name
|
||||||
assert.Equal(t, "file1", file.Name())
|
assert.Equal(t, "file1", file.Name())
|
||||||
|
|
|
@ -46,7 +46,7 @@ func TestRcGetVFS(t *testing.T) {
|
||||||
assert.Contains(t, err.Error(), "no VFS found with name")
|
assert.Contains(t, err.Error(), "no VFS found with name")
|
||||||
assert.Nil(t, vfs)
|
assert.Nil(t, vfs)
|
||||||
|
|
||||||
opt := vfscommon.DefaultOpt
|
opt := vfscommon.Opt
|
||||||
opt.NoModTime = true
|
opt.NoModTime = true
|
||||||
vfs3 := New(r.Fremote, &opt)
|
vfs3 := New(r.Fremote, &opt)
|
||||||
defer vfs3.Shutdown()
|
defer vfs3.Shutdown()
|
||||||
|
|
|
@ -30,7 +30,7 @@ var (
|
||||||
|
|
||||||
// Create a file and open it with the flags passed in
|
// Create a file and open it with the flags passed in
|
||||||
func rwHandleCreateFlags(t *testing.T, create bool, filename string, flags int) (r *fstest.Run, vfs *VFS, fh *RWFileHandle) {
|
func rwHandleCreateFlags(t *testing.T, create bool, filename string, flags int) (r *fstest.Run, vfs *VFS, fh *RWFileHandle) {
|
||||||
opt := vfscommon.DefaultOpt
|
opt := vfscommon.Opt
|
||||||
opt.CacheMode = vfscommon.CacheModeFull
|
opt.CacheMode = vfscommon.CacheModeFull
|
||||||
opt.WriteBack = writeBackDelay
|
opt.WriteBack = writeBackDelay
|
||||||
r, vfs = newTestVFSOpt(t, &opt)
|
r, vfs = newTestVFSOpt(t, &opt)
|
||||||
|
@ -634,7 +634,7 @@ func testRWFileHandleOpenTest(t *testing.T, vfs *VFS, test *openTest) {
|
||||||
func TestRWFileHandleOpenTests(t *testing.T) {
|
func TestRWFileHandleOpenTests(t *testing.T) {
|
||||||
for _, cacheMode := range []vfscommon.CacheMode{vfscommon.CacheModeWrites, vfscommon.CacheModeFull} {
|
for _, cacheMode := range []vfscommon.CacheMode{vfscommon.CacheModeWrites, vfscommon.CacheModeFull} {
|
||||||
t.Run(cacheMode.String(), func(t *testing.T) {
|
t.Run(cacheMode.String(), func(t *testing.T) {
|
||||||
opt := vfscommon.DefaultOpt
|
opt := vfscommon.Opt
|
||||||
opt.CacheMode = cacheMode
|
opt.CacheMode = cacheMode
|
||||||
opt.WriteBack = writeBackDelay
|
opt.WriteBack = writeBackDelay
|
||||||
_, vfs := newTestVFSOpt(t, &opt)
|
_, vfs := newTestVFSOpt(t, &opt)
|
||||||
|
@ -685,7 +685,7 @@ func TestRWFileModTimeWithOpenWriters(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRWCacheRename(t *testing.T) {
|
func TestRWCacheRename(t *testing.T) {
|
||||||
opt := vfscommon.DefaultOpt
|
opt := vfscommon.Opt
|
||||||
opt.CacheMode = vfscommon.CacheModeFull
|
opt.CacheMode = vfscommon.CacheModeFull
|
||||||
opt.WriteBack = writeBackDelay
|
opt.WriteBack = writeBackDelay
|
||||||
r, vfs := newTestVFSOpt(t, &opt)
|
r, vfs := newTestVFSOpt(t, &opt)
|
||||||
|
@ -719,7 +719,7 @@ func TestRWCacheRename(t *testing.T) {
|
||||||
//
|
//
|
||||||
// See: https://github.com/rclone/rclone/issues/6053
|
// See: https://github.com/rclone/rclone/issues/6053
|
||||||
func TestRWCacheUpdate(t *testing.T) {
|
func TestRWCacheUpdate(t *testing.T) {
|
||||||
opt := vfscommon.DefaultOpt
|
opt := vfscommon.Opt
|
||||||
opt.CacheMode = vfscommon.CacheModeFull
|
opt.CacheMode = vfscommon.CacheModeFull
|
||||||
opt.WriteBack = writeBackDelay
|
opt.WriteBack = writeBackDelay
|
||||||
opt.DirCacheTime = fs.Duration(100 * time.Millisecond)
|
opt.DirCacheTime = fs.Duration(100 * time.Millisecond)
|
||||||
|
|
|
@ -204,7 +204,7 @@ func New(f fs.Fs, opt *vfscommon.Options) *VFS {
|
||||||
if opt != nil {
|
if opt != nil {
|
||||||
vfs.Opt = *opt
|
vfs.Opt = *opt
|
||||||
} else {
|
} else {
|
||||||
vfs.Opt = vfscommon.DefaultOpt
|
vfs.Opt = vfscommon.Opt
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill out anything else
|
// Fill out anything else
|
||||||
|
@ -776,7 +776,7 @@ func (vfs *VFS) AddVirtual(remote string, size int64, isDir bool) (err error) {
|
||||||
} else {
|
} else {
|
||||||
// Create parent of virtual directory since backend can't have empty directories
|
// Create parent of virtual directory since backend can't have empty directories
|
||||||
parent, leaf = path.Split(remote)
|
parent, leaf = path.Split(remote)
|
||||||
dir, err = vfs.mkdirAll(parent, vfs.Opt.DirPerms)
|
dir, err = vfs.mkdirAll(parent, os.FileMode(vfs.Opt.DirPerms))
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -34,12 +34,12 @@ func TestCaseSensitivity(t *testing.T) {
|
||||||
file3 := r.WriteObject(ctx, "FilEb", "data3", t3)
|
file3 := r.WriteObject(ctx, "FilEb", "data3", t3)
|
||||||
|
|
||||||
// Create a case-Sensitive and case-INsensitive VFS
|
// Create a case-Sensitive and case-INsensitive VFS
|
||||||
optCS := vfscommon.DefaultOpt
|
optCS := vfscommon.Opt
|
||||||
optCS.CaseInsensitive = false
|
optCS.CaseInsensitive = false
|
||||||
vfsCS := New(r.Fremote, &optCS)
|
vfsCS := New(r.Fremote, &optCS)
|
||||||
defer cleanupVFS(t, vfsCS)
|
defer cleanupVFS(t, vfsCS)
|
||||||
|
|
||||||
optCI := vfscommon.DefaultOpt
|
optCI := vfscommon.Opt
|
||||||
optCI.CaseInsensitive = true
|
optCI.CaseInsensitive = true
|
||||||
vfsCI := New(r.Fremote, &optCI)
|
vfsCI := New(r.Fremote, &optCI)
|
||||||
defer cleanupVFS(t, vfsCI)
|
defer cleanupVFS(t, vfsCI)
|
||||||
|
@ -179,7 +179,7 @@ func TestUnicodeNormalization(t *testing.T) {
|
||||||
r.CheckRemoteItems(t, file1, file2)
|
r.CheckRemoteItems(t, file1, file2)
|
||||||
|
|
||||||
// Create VFS
|
// Create VFS
|
||||||
opt := vfscommon.DefaultOpt
|
opt := vfscommon.Opt
|
||||||
vfs := New(r.Fremote, &opt)
|
vfs := New(r.Fremote, &opt)
|
||||||
defer cleanupVFS(t, vfs)
|
defer cleanupVFS(t, vfs)
|
||||||
|
|
||||||
|
|
|
@ -138,10 +138,8 @@ func TestVFSNew(t *testing.T) {
|
||||||
r, vfs := newTestVFS(t)
|
r, vfs := newTestVFS(t)
|
||||||
|
|
||||||
// Check making a VFS with nil options
|
// Check making a VFS with nil options
|
||||||
var defaultOpt = vfscommon.DefaultOpt
|
var defaultOpt = vfscommon.Opt
|
||||||
defaultOpt.DirPerms |= os.ModeDir
|
defaultOpt.Init()
|
||||||
assert.Equal(t, vfs.Opt, defaultOpt)
|
|
||||||
assert.Equal(t, vfs.f, r.Fremote)
|
|
||||||
|
|
||||||
checkActiveCacheEntries(1)
|
checkActiveCacheEntries(1)
|
||||||
|
|
||||||
|
@ -164,14 +162,14 @@ func TestVFSNew(t *testing.T) {
|
||||||
|
|
||||||
// TestVFSNewWithOpts sees if the New command works properly
|
// TestVFSNewWithOpts sees if the New command works properly
|
||||||
func TestVFSNewWithOpts(t *testing.T) {
|
func TestVFSNewWithOpts(t *testing.T) {
|
||||||
var opt = vfscommon.DefaultOpt
|
var opt = vfscommon.Opt
|
||||||
opt.DirPerms = 0777
|
opt.DirPerms = 0777
|
||||||
opt.FilePerms = 0666
|
opt.FilePerms = 0666
|
||||||
opt.Umask = 0002
|
opt.Umask = 0002
|
||||||
_, vfs := newTestVFSOpt(t, &opt)
|
_, vfs := newTestVFSOpt(t, &opt)
|
||||||
|
|
||||||
assert.Equal(t, os.FileMode(0775)|os.ModeDir, vfs.Opt.DirPerms)
|
assert.Equal(t, vfscommon.FileMode(0775)|vfscommon.FileMode(os.ModeDir), vfs.Opt.DirPerms)
|
||||||
assert.Equal(t, os.FileMode(0664), vfs.Opt.FilePerms)
|
assert.Equal(t, vfscommon.FileMode(0664), vfs.Opt.FilePerms)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestVFSRoot checks root directory is present and correct
|
// TestVFSRoot checks root directory is present and correct
|
||||||
|
@ -182,7 +180,7 @@ func TestVFSRoot(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Equal(t, vfs.root, root)
|
assert.Equal(t, vfs.root, root)
|
||||||
assert.True(t, root.IsDir())
|
assert.True(t, root.IsDir())
|
||||||
assert.Equal(t, vfs.Opt.DirPerms.Perm(), root.Mode().Perm())
|
assert.Equal(t, os.FileMode(vfs.Opt.DirPerms).Perm(), root.Mode().Perm())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVFSStat(t *testing.T) {
|
func TestVFSStat(t *testing.T) {
|
||||||
|
|
|
@ -104,7 +104,7 @@ func newTestCacheOpt(t *testing.T, opt vfscommon.Options) (r *fstest.Run, c *Cac
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestCache(t *testing.T) (r *fstest.Run, c *Cache) {
|
func newTestCache(t *testing.T) (r *fstest.Run, c *Cache) {
|
||||||
opt := vfscommon.DefaultOpt
|
opt := vfscommon.Opt
|
||||||
|
|
||||||
// Disable the cache cleaner as it interferes with these tests
|
// Disable the cache cleaner as it interferes with these tests
|
||||||
opt.CachePollInterval = 0
|
opt.CachePollInterval = 0
|
||||||
|
@ -627,7 +627,7 @@ func TestCacheRename(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCacheCleaner(t *testing.T) {
|
func TestCacheCleaner(t *testing.T) {
|
||||||
opt := vfscommon.DefaultOpt
|
opt := vfscommon.Opt
|
||||||
opt.CachePollInterval = fs.Duration(10 * time.Millisecond)
|
opt.CachePollInterval = fs.Duration(10 * time.Millisecond)
|
||||||
opt.CacheMaxAge = fs.Duration(20 * time.Millisecond)
|
opt.CacheMaxAge = fs.Duration(20 * time.Millisecond)
|
||||||
_, c := newTestCacheOpt(t, opt)
|
_, c := newTestCacheOpt(t, opt)
|
||||||
|
|
|
@ -93,7 +93,7 @@ func TestDownloaders(t *testing.T) {
|
||||||
t: t,
|
t: t,
|
||||||
size: size,
|
size: size,
|
||||||
}
|
}
|
||||||
opt := vfscommon.DefaultOpt
|
opt := vfscommon.Opt
|
||||||
dls := New(item, &opt, remote, src)
|
dls := New(item, &opt, remote, src)
|
||||||
return item, dls
|
return item, dls
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ import (
|
||||||
var zeroes = string(make([]byte, 100))
|
var zeroes = string(make([]byte, 100))
|
||||||
|
|
||||||
func newItemTestCache(t *testing.T) (r *fstest.Run, c *Cache) {
|
func newItemTestCache(t *testing.T) (r *fstest.Run, c *Cache) {
|
||||||
opt := vfscommon.DefaultOpt
|
opt := vfscommon.Opt
|
||||||
|
|
||||||
// Disable the cache cleaner as it interferes with these tests
|
// Disable the cache cleaner as it interferes with these tests
|
||||||
opt.CachePollInterval = 0
|
opt.CachePollInterval = 0
|
||||||
|
|
|
@ -17,7 +17,7 @@ import (
|
||||||
|
|
||||||
func newTestWriteBack(t *testing.T) (wb *WriteBack, cancel func()) {
|
func newTestWriteBack(t *testing.T) (wb *WriteBack, cancel func()) {
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
opt := vfscommon.DefaultOpt
|
opt := vfscommon.Opt
|
||||||
opt.WriteBack = fs.Duration(100 * time.Millisecond)
|
opt.WriteBack = fs.Duration(100 * time.Millisecond)
|
||||||
wb = New(ctx, &opt)
|
wb = New(ctx, &opt)
|
||||||
return wb, cancel
|
return wb, cancel
|
||||||
|
|
40
vfs/vfscommon/filemode.go
Normal file
40
vfs/vfscommon/filemode.go
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
package vfscommon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/rclone/rclone/fs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// FileMode is a command line friendly os.FileMode
|
||||||
|
type FileMode os.FileMode
|
||||||
|
|
||||||
|
// String turns FileMode into a string
|
||||||
|
func (x FileMode) String() string {
|
||||||
|
return fmt.Sprintf("%03o", x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a FileMode
|
||||||
|
func (x *FileMode) Set(s string) error {
|
||||||
|
i, err := strconv.ParseInt(s, 8, 32)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("bad FileMode - must be octal digits: %w", err)
|
||||||
|
}
|
||||||
|
*x = (FileMode)(i)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Type of the value
|
||||||
|
func (x FileMode) Type() string {
|
||||||
|
return "FileMode"
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON makes sure the value can be parsed as a string or integer in JSON
|
||||||
|
func (x *FileMode) UnmarshalJSON(in []byte) error {
|
||||||
|
return fs.UnmarshalJSONFlag(in, x, func(i int64) error {
|
||||||
|
*x = FileMode(i)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
77
vfs/vfscommon/filemode_test.go
Normal file
77
vfs/vfscommon/filemode_test.go
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
package vfscommon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/rclone/rclone/fs"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Check it satisfies the interfaces
|
||||||
|
var (
|
||||||
|
_ fs.Flagger = (*FileMode)(nil)
|
||||||
|
_ fs.FlaggerNP = FileMode(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFileModeString(t *testing.T) {
|
||||||
|
for _, test := range []struct {
|
||||||
|
in FileMode
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
{0, "000"},
|
||||||
|
{0666, "666"},
|
||||||
|
{02666, "2666"},
|
||||||
|
} {
|
||||||
|
got := test.in.String()
|
||||||
|
assert.Equal(t, test.want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileModeSet(t *testing.T) {
|
||||||
|
for _, test := range []struct {
|
||||||
|
in string
|
||||||
|
want FileMode
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
{"0", 0, false},
|
||||||
|
{"0666", 0666, false},
|
||||||
|
{"666", 0666, false},
|
||||||
|
{"2666", 02666, false},
|
||||||
|
{"999", 0, true},
|
||||||
|
} {
|
||||||
|
got := FileMode(0)
|
||||||
|
err := got.Set(test.in)
|
||||||
|
if test.err {
|
||||||
|
require.Error(t, err, test.in)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err, test.in)
|
||||||
|
}
|
||||||
|
assert.Equal(t, test.want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFileModeUnmarshalJSON(t *testing.T) {
|
||||||
|
for _, test := range []struct {
|
||||||
|
in string
|
||||||
|
want FileMode
|
||||||
|
err bool
|
||||||
|
}{
|
||||||
|
{`"0"`, 0, false},
|
||||||
|
{`"666"`, 0666, false},
|
||||||
|
{`"02666"`, 02666, false},
|
||||||
|
{`"999"`, 0, true},
|
||||||
|
{`438`, 0666, false},
|
||||||
|
{`"999"`, 0, true},
|
||||||
|
} {
|
||||||
|
var ss FileMode
|
||||||
|
err := json.Unmarshal([]byte(test.in), &ss)
|
||||||
|
if test.err {
|
||||||
|
require.Error(t, err, test.in)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err, test.in)
|
||||||
|
}
|
||||||
|
assert.Equal(t, test.want, ss, test.in)
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,75 +8,194 @@ import (
|
||||||
"github.com/rclone/rclone/fs"
|
"github.com/rclone/rclone/fs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options is options for creating the vfs
|
// OptionsInfo describes the Options in use
|
||||||
type Options struct {
|
var OptionsInfo = fs.Options{{
|
||||||
NoSeek bool // don't allow seeking if set
|
Name: "no_modtime",
|
||||||
NoChecksum bool // don't check checksums if set
|
Default: false,
|
||||||
ReadOnly bool // if set VFS is read only
|
Help: "Don't read/write the modification time (can speed things up)",
|
||||||
NoModTime bool // don't read mod times for files
|
Groups: "VFS",
|
||||||
DirCacheTime fs.Duration // how long to consider directory listing cache valid
|
}, {
|
||||||
Refresh bool // refreshes the directory listing recursively on start
|
Name: "no_checksum",
|
||||||
PollInterval fs.Duration
|
Default: false,
|
||||||
Umask int
|
Help: "Don't compare checksums on up/download",
|
||||||
UID uint32
|
Groups: "VFS",
|
||||||
GID uint32
|
}, {
|
||||||
DirPerms os.FileMode
|
Name: "no_seek",
|
||||||
FilePerms os.FileMode
|
Default: false,
|
||||||
ChunkSize fs.SizeSuffix // if > 0 read files in chunks
|
Help: "Don't allow seeking in files",
|
||||||
ChunkSizeLimit fs.SizeSuffix // if > ChunkSize double the chunk size after each chunk until reached
|
Groups: "VFS",
|
||||||
CacheMode CacheMode
|
}, {
|
||||||
CacheMaxAge fs.Duration
|
Name: "dir_cache_time",
|
||||||
CacheMaxSize fs.SizeSuffix
|
Default: fs.Duration(5 * 60 * time.Second),
|
||||||
CacheMinFreeSpace fs.SizeSuffix
|
Help: "Time to cache directory entries for",
|
||||||
CachePollInterval fs.Duration
|
Groups: "VFS",
|
||||||
CaseInsensitive bool
|
}, {
|
||||||
BlockNormDupes bool
|
Name: "vfs_refresh",
|
||||||
WriteWait fs.Duration // time to wait for in-sequence write
|
Default: false,
|
||||||
ReadWait fs.Duration // time to wait for in-sequence read
|
Help: "Refreshes the directory cache recursively in the background on start",
|
||||||
WriteBack fs.Duration // time to wait before writing back dirty files
|
Groups: "VFS",
|
||||||
ReadAhead fs.SizeSuffix // bytes to read ahead in cache mode "full"
|
}, {
|
||||||
UsedIsSize bool // if true, use the `rclone size` algorithm for Used size
|
Name: "poll_interval",
|
||||||
FastFingerprint bool // if set use fast fingerprints
|
Default: fs.Duration(time.Minute),
|
||||||
DiskSpaceTotalSize fs.SizeSuffix
|
Help: "Time to wait between polling for changes, must be smaller than dir-cache-time and only on supported remotes (set 0 to disable)",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "read_only",
|
||||||
|
Default: false,
|
||||||
|
Help: "Only allow read-only access",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "vfs_cache_mode",
|
||||||
|
Default: CacheModeOff,
|
||||||
|
Help: "Cache mode off|minimal|writes|full",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "vfs_cache_poll_interval",
|
||||||
|
Default: fs.Duration(60 * time.Second),
|
||||||
|
Help: "Interval to poll the cache for stale objects",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "vfs_cache_max_age",
|
||||||
|
Default: fs.Duration(3600 * time.Second),
|
||||||
|
Help: "Max time since last access of objects in the cache",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "vfs_cache_max_size",
|
||||||
|
Default: fs.SizeSuffix(-1),
|
||||||
|
Help: "Max total size of objects in the cache",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "vfs_cache_min_free_space",
|
||||||
|
Default: fs.SizeSuffix(-1),
|
||||||
|
Help: "Target minimum free space on the disk containing the cache",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "vfs_read_chunk_size",
|
||||||
|
Default: 128 * fs.Mebi,
|
||||||
|
Help: "Read the source objects in chunks",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "vfs_read_chunk_size_limit",
|
||||||
|
Default: fs.SizeSuffix(-1),
|
||||||
|
Help: "If greater than --vfs-read-chunk-size, double the chunk size after each chunk read, until the limit is reached ('off' is unlimited)",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "dir_perms",
|
||||||
|
Default: FileMode(0777),
|
||||||
|
Help: "Directory permissions",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "file_perms",
|
||||||
|
Default: FileMode(0666),
|
||||||
|
Help: "File permissions",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "vfs_case_insensitive",
|
||||||
|
Default: runtime.GOOS == "windows" || runtime.GOOS == "darwin", // default to true on Windows and Mac, false otherwise,
|
||||||
|
Help: "If a file name not found, find a case insensitive match",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "vfs_block_norm_dupes",
|
||||||
|
Default: false,
|
||||||
|
Help: "If duplicate filenames exist in the same directory (after normalization), log an error and hide the duplicates (may have a performance cost)",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "vfs_write_wait",
|
||||||
|
Default: fs.Duration(1000 * time.Millisecond),
|
||||||
|
Help: "Time to wait for in-sequence write before giving error",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "vfs_read_wait",
|
||||||
|
Default: fs.Duration(20 * time.Millisecond),
|
||||||
|
Help: "Time to wait for in-sequence read before seeking",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "vfs_write_back",
|
||||||
|
Default: fs.Duration(5 * time.Second),
|
||||||
|
Help: "Time to writeback files after last use when using cache",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "vfs_read_ahead",
|
||||||
|
Default: 0 * fs.Mebi,
|
||||||
|
Help: "Extra read ahead over --buffer-size when using cache-mode full",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "vfs_used_is_size",
|
||||||
|
Default: false,
|
||||||
|
Help: "Use the `rclone size` algorithm for Used size",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "vfs_fast_fingerprint",
|
||||||
|
Default: false,
|
||||||
|
Help: "Use fast (less accurate) fingerprints for change detection",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "vfs_disk_space_total_size",
|
||||||
|
Default: fs.SizeSuffix(-1),
|
||||||
|
Help: "Specify the total space of disk",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "umask",
|
||||||
|
Default: FileMode(getUmask()),
|
||||||
|
Help: "Override the permission bits set by the filesystem (not supported on Windows)",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "uid",
|
||||||
|
Default: getUID(),
|
||||||
|
Help: "Override the uid field set by the filesystem (not supported on Windows)",
|
||||||
|
Groups: "VFS",
|
||||||
|
}, {
|
||||||
|
Name: "gid",
|
||||||
|
Default: getGID(),
|
||||||
|
Help: "Override the gid field set by the filesystem (not supported on Windows)",
|
||||||
|
Groups: "VFS",
|
||||||
|
}}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
fs.RegisterGlobalOptions(fs.OptionsInfo{Name: "vfs", Opt: &Opt, Options: OptionsInfo})
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultOpt is the default values uses for Opt
|
// Options is options for creating the vfs
|
||||||
var DefaultOpt = Options{
|
type Options struct {
|
||||||
NoModTime: false,
|
NoSeek bool `config:"no_seek"` // don't allow seeking if set
|
||||||
NoChecksum: false,
|
NoChecksum bool `config:"no_checksum"` // don't check checksums if set
|
||||||
NoSeek: false,
|
ReadOnly bool `config:"read_only"` // if set VFS is read only
|
||||||
DirCacheTime: fs.Duration(5 * 60 * time.Second),
|
NoModTime bool `config:"no_modtime"` // don't read mod times for files
|
||||||
Refresh: false,
|
DirCacheTime fs.Duration `config:"dir_cache_time"` // how long to consider directory listing cache valid
|
||||||
PollInterval: fs.Duration(time.Minute),
|
Refresh bool `config:"vfs_refresh"` // refreshes the directory listing recursively on start
|
||||||
ReadOnly: false,
|
PollInterval fs.Duration `config:"poll_interval"`
|
||||||
Umask: 0,
|
Umask FileMode `config:"umask"`
|
||||||
UID: ^uint32(0), // these values instruct WinFSP-FUSE to use the current user
|
UID uint32 `config:"uid"`
|
||||||
GID: ^uint32(0), // overridden for non windows in mount_unix.go
|
GID uint32 `config:"gid"`
|
||||||
DirPerms: os.FileMode(0777),
|
DirPerms FileMode `config:"dir_perms"`
|
||||||
FilePerms: os.FileMode(0666),
|
FilePerms FileMode `config:"file_perms"`
|
||||||
CacheMode: CacheModeOff,
|
ChunkSize fs.SizeSuffix `config:"vfs_read_chunk_size"` // if > 0 read files in chunks
|
||||||
CacheMaxAge: fs.Duration(3600 * time.Second),
|
ChunkSizeLimit fs.SizeSuffix `config:"vfs_read_chunk_size_limit"` // if > ChunkSize double the chunk size after each chunk until reached
|
||||||
CachePollInterval: fs.Duration(60 * time.Second),
|
CacheMode CacheMode `config:"vfs_cache_mode"`
|
||||||
ChunkSize: 128 * fs.Mebi,
|
CacheMaxAge fs.Duration `config:"vfs_cache_max_age"`
|
||||||
ChunkSizeLimit: -1,
|
CacheMaxSize fs.SizeSuffix `config:"vfs_cache_max_size"`
|
||||||
CacheMaxSize: -1,
|
CacheMinFreeSpace fs.SizeSuffix `config:"vfs_cache_min_free_space"`
|
||||||
CacheMinFreeSpace: -1,
|
CachePollInterval fs.Duration `config:"vfs_cache_poll_interval"`
|
||||||
CaseInsensitive: runtime.GOOS == "windows" || runtime.GOOS == "darwin", // default to true on Windows and Mac, false otherwise
|
CaseInsensitive bool `config:"vfs_case_insensitive"`
|
||||||
WriteWait: fs.Duration(1000 * time.Millisecond),
|
BlockNormDupes bool `config:"vfs_block_norm_dupes"`
|
||||||
ReadWait: fs.Duration(20 * time.Millisecond),
|
WriteWait fs.Duration `config:"vfs_write_wait"` // time to wait for in-sequence write
|
||||||
WriteBack: fs.Duration(5 * time.Second),
|
ReadWait fs.Duration `config:"vfs_read_wait"` // time to wait for in-sequence read
|
||||||
ReadAhead: 0 * fs.Mebi,
|
WriteBack fs.Duration `config:"vfs_write_back"` // time to wait before writing back dirty files
|
||||||
UsedIsSize: false,
|
ReadAhead fs.SizeSuffix `config:"vfs_read_ahead"` // bytes to read ahead in cache mode "full"
|
||||||
DiskSpaceTotalSize: -1,
|
UsedIsSize bool `config:"vfs_used_is_size"` // if true, use the `rclone size` algorithm for Used size
|
||||||
|
FastFingerprint bool `config:"vfs_fast_fingerprint"` // if set use fast fingerprints
|
||||||
|
DiskSpaceTotalSize fs.SizeSuffix `config:"vfs_disk_space_total_size"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Opt is the default options modified by the environment variables and command line flags
|
||||||
|
var Opt Options
|
||||||
|
|
||||||
// Init the options, making sure everything is within range
|
// Init the options, making sure everything is within range
|
||||||
func (opt *Options) Init() {
|
func (opt *Options) Init() {
|
||||||
// Mask the permissions with the umask
|
// Mask the permissions with the umask
|
||||||
opt.DirPerms &= ^os.FileMode(opt.Umask)
|
opt.DirPerms &= ^opt.Umask
|
||||||
opt.FilePerms &= ^os.FileMode(opt.Umask)
|
opt.FilePerms &= ^opt.Umask
|
||||||
|
|
||||||
// Make sure directories are returned as directories
|
// Make sure directories are returned as directories
|
||||||
opt.DirPerms |= os.ModeDir
|
opt.DirPerms |= FileMode(os.ModeDir)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
18
vfs/vfscommon/vfsflags_non_unix.go
Normal file
18
vfs/vfscommon/vfsflags_non_unix.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
//go:build !linux && !darwin && !freebsd
|
||||||
|
|
||||||
|
package vfscommon
|
||||||
|
|
||||||
|
// get the current umask
|
||||||
|
func getUmask() int {
|
||||||
|
return 0000
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the current uid
|
||||||
|
func getUID() uint32 {
|
||||||
|
return ^uint32(0) // these values instruct WinFSP-FUSE to use the current user
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the current gid
|
||||||
|
func getGID() uint32 {
|
||||||
|
return ^uint32(0) // these values instruct WinFSP-FUSE to use the current user
|
||||||
|
}
|
24
vfs/vfscommon/vfsflags_unix.go
Normal file
24
vfs/vfscommon/vfsflags_unix.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
//go:build linux || darwin || freebsd
|
||||||
|
|
||||||
|
package vfscommon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
// get the current umask
|
||||||
|
func getUmask() int {
|
||||||
|
umask := unix.Umask(0) // read the umask
|
||||||
|
unix.Umask(umask) // set it back to what it was
|
||||||
|
return umask
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the current uid
|
||||||
|
func getUID() uint32 {
|
||||||
|
return uint32(unix.Geteuid())
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the current gid
|
||||||
|
func getGID() uint32 {
|
||||||
|
return uint32(unix.Getegid())
|
||||||
|
}
|
|
@ -1,32 +0,0 @@
|
||||||
package vfsflags
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FileMode is a command line friendly os.FileMode
|
|
||||||
type FileMode struct {
|
|
||||||
Mode *os.FileMode
|
|
||||||
}
|
|
||||||
|
|
||||||
// String turns FileMode into a string
|
|
||||||
func (x *FileMode) String() string {
|
|
||||||
return fmt.Sprintf("0%3o", *x.Mode)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a FileMode
|
|
||||||
func (x *FileMode) Set(s string) error {
|
|
||||||
i, err := strconv.ParseInt(s, 8, 32)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("bad FileMode - must be octal digits: %w", err)
|
|
||||||
}
|
|
||||||
*x.Mode = (os.FileMode)(i)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Type of the value
|
|
||||||
func (x *FileMode) Type() string {
|
|
||||||
return "FileMode"
|
|
||||||
}
|
|
|
@ -3,45 +3,11 @@ package vfsflags
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/rclone/rclone/fs/config/flags"
|
"github.com/rclone/rclone/fs/config/flags"
|
||||||
"github.com/rclone/rclone/fs/rc"
|
|
||||||
"github.com/rclone/rclone/vfs/vfscommon"
|
"github.com/rclone/rclone/vfs/vfscommon"
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Options set by command line flags
|
|
||||||
var (
|
|
||||||
Opt = vfscommon.DefaultOpt
|
|
||||||
DirPerms = &FileMode{Mode: &Opt.DirPerms}
|
|
||||||
FilePerms = &FileMode{Mode: &Opt.FilePerms}
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddFlags adds the non filing system specific flags to the command
|
// AddFlags adds the non filing system specific flags to the command
|
||||||
func AddFlags(flagSet *pflag.FlagSet) {
|
func AddFlags(flagSet *pflag.FlagSet) {
|
||||||
rc.AddOption("vfs", &Opt)
|
flags.AddFlagsFromOptions(flagSet, "", vfscommon.OptionsInfo)
|
||||||
flags.BoolVarP(flagSet, &Opt.NoModTime, "no-modtime", "", Opt.NoModTime, "Don't read/write the modification time (can speed things up)", "VFS")
|
|
||||||
flags.BoolVarP(flagSet, &Opt.NoChecksum, "no-checksum", "", Opt.NoChecksum, "Don't compare checksums on up/download", "VFS")
|
|
||||||
flags.BoolVarP(flagSet, &Opt.NoSeek, "no-seek", "", Opt.NoSeek, "Don't allow seeking in files", "VFS")
|
|
||||||
flags.FVarP(flagSet, &Opt.DirCacheTime, "dir-cache-time", "", "Time to cache directory entries for", "VFS")
|
|
||||||
flags.BoolVarP(flagSet, &Opt.Refresh, "vfs-refresh", "", Opt.Refresh, "Refreshes the directory cache recursively in the background on start", "VFS")
|
|
||||||
flags.FVarP(flagSet, &Opt.PollInterval, "poll-interval", "", "Time to wait between polling for changes, must be smaller than dir-cache-time and only on supported remotes (set 0 to disable)", "VFS")
|
|
||||||
flags.BoolVarP(flagSet, &Opt.ReadOnly, "read-only", "", Opt.ReadOnly, "Only allow read-only access", "VFS")
|
|
||||||
flags.FVarP(flagSet, &Opt.CacheMode, "vfs-cache-mode", "", "Cache mode off|minimal|writes|full", "VFS")
|
|
||||||
flags.FVarP(flagSet, &Opt.CachePollInterval, "vfs-cache-poll-interval", "", "Interval to poll the cache for stale objects", "VFS")
|
|
||||||
flags.FVarP(flagSet, &Opt.CacheMaxAge, "vfs-cache-max-age", "", "Max time since last access of objects in the cache", "VFS")
|
|
||||||
flags.FVarP(flagSet, &Opt.CacheMaxSize, "vfs-cache-max-size", "", "Max total size of objects in the cache", "VFS")
|
|
||||||
flags.FVarP(flagSet, &Opt.CacheMinFreeSpace, "vfs-cache-min-free-space", "", "Target minimum free space on the disk containing the cache", "VFS")
|
|
||||||
flags.FVarP(flagSet, &Opt.ChunkSize, "vfs-read-chunk-size", "", "Read the source objects in chunks", "VFS")
|
|
||||||
flags.FVarP(flagSet, &Opt.ChunkSizeLimit, "vfs-read-chunk-size-limit", "", "If greater than --vfs-read-chunk-size, double the chunk size after each chunk read, until the limit is reached ('off' is unlimited)", "VFS")
|
|
||||||
flags.FVarP(flagSet, DirPerms, "dir-perms", "", "Directory permissions", "VFS")
|
|
||||||
flags.FVarP(flagSet, FilePerms, "file-perms", "", "File permissions", "VFS")
|
|
||||||
flags.BoolVarP(flagSet, &Opt.CaseInsensitive, "vfs-case-insensitive", "", Opt.CaseInsensitive, "If a file name not found, find a case insensitive match", "VFS")
|
|
||||||
flags.BoolVarP(flagSet, &Opt.BlockNormDupes, "vfs-block-norm-dupes", "", Opt.BlockNormDupes, "If duplicate filenames exist in the same directory (after normalization), log an error and hide the duplicates (may have a performance cost)", "VFS")
|
|
||||||
flags.FVarP(flagSet, &Opt.WriteWait, "vfs-write-wait", "", "Time to wait for in-sequence write before giving error", "VFS")
|
|
||||||
flags.FVarP(flagSet, &Opt.ReadWait, "vfs-read-wait", "", "Time to wait for in-sequence read before seeking", "VFS")
|
|
||||||
flags.FVarP(flagSet, &Opt.WriteBack, "vfs-write-back", "", "Time to writeback files after last use when using cache", "VFS")
|
|
||||||
flags.FVarP(flagSet, &Opt.ReadAhead, "vfs-read-ahead", "", "Extra read ahead over --buffer-size when using cache-mode full", "VFS")
|
|
||||||
flags.BoolVarP(flagSet, &Opt.UsedIsSize, "vfs-used-is-size", "", Opt.UsedIsSize, "Use the `rclone size` algorithm for Used size", "VFS")
|
|
||||||
flags.BoolVarP(flagSet, &Opt.FastFingerprint, "vfs-fast-fingerprint", "", Opt.FastFingerprint, "Use fast (less accurate) fingerprints for change detection", "VFS")
|
|
||||||
flags.FVarP(flagSet, &Opt.DiskSpaceTotalSize, "vfs-disk-space-total-size", "", "Specify the total space of disk", "VFS")
|
|
||||||
platformFlags(flagSet)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
//go:build !linux && !darwin && !freebsd
|
|
||||||
|
|
||||||
package vfsflags
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/spf13/pflag"
|
|
||||||
)
|
|
||||||
|
|
||||||
// add any extra platform specific flags
|
|
||||||
func platformFlags(flags *pflag.FlagSet) {
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
//go:build linux || darwin || freebsd
|
|
||||||
|
|
||||||
package vfsflags
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/rclone/rclone/fs/config/flags"
|
|
||||||
"github.com/spf13/pflag"
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
// add any extra platform specific flags
|
|
||||||
func platformFlags(flagSet *pflag.FlagSet) {
|
|
||||||
Opt.Umask = unix.Umask(0) // read the umask
|
|
||||||
unix.Umask(Opt.Umask) // set it back to what it was
|
|
||||||
flags.IntVarP(flagSet, &Opt.Umask, "umask", "", Opt.Umask, "Override the permission bits set by the filesystem (not supported on Windows)", "VFS")
|
|
||||||
Opt.UID = uint32(unix.Geteuid())
|
|
||||||
Opt.GID = uint32(unix.Getegid())
|
|
||||||
flags.Uint32VarP(flagSet, &Opt.UID, "uid", "", Opt.UID, "Override the uid field set by the filesystem (not supported on Windows)", "VFS")
|
|
||||||
flags.Uint32VarP(flagSet, &Opt.GID, "gid", "", Opt.GID, "Override the gid field set by the filesystem (not supported on Windows)", "VFS")
|
|
||||||
}
|
|
|
@ -26,7 +26,6 @@ import (
|
||||||
"github.com/rclone/rclone/fs/walk"
|
"github.com/rclone/rclone/fs/walk"
|
||||||
"github.com/rclone/rclone/fstest"
|
"github.com/rclone/rclone/fstest"
|
||||||
"github.com/rclone/rclone/vfs/vfscommon"
|
"github.com/rclone/rclone/vfs/vfscommon"
|
||||||
"github.com/rclone/rclone/vfs/vfsflags"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -62,7 +61,7 @@ func RunTests(t *testing.T, useVFS bool, minimumRequiredCacheMode vfscommon.Cach
|
||||||
if test.cacheMode < minimumRequiredCacheMode {
|
if test.cacheMode < minimumRequiredCacheMode {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
vfsOpt := vfsflags.Opt
|
vfsOpt := vfscommon.Opt
|
||||||
vfsOpt.CacheMode = test.cacheMode
|
vfsOpt.CacheMode = test.cacheMode
|
||||||
vfsOpt.WriteBack = test.writeBack
|
vfsOpt.WriteBack = test.writeBack
|
||||||
run = newRun(useVFS, &vfsOpt, mountFn)
|
run = newRun(useVFS, &vfsOpt, mountFn)
|
||||||
|
@ -235,10 +234,10 @@ func (r *Run) readLocal(t *testing.T, dir dirMap, filePath string) {
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
dir[name+"/"] = struct{}{}
|
dir[name+"/"] = struct{}{}
|
||||||
r.readLocal(t, dir, name)
|
r.readLocal(t, dir, name)
|
||||||
assert.Equal(t, r.vfsOpt.DirPerms&os.ModePerm, fi.Mode().Perm())
|
assert.Equal(t, os.FileMode(r.vfsOpt.DirPerms)&os.ModePerm, fi.Mode().Perm())
|
||||||
} else {
|
} else {
|
||||||
dir[fmt.Sprintf("%s %d", name, fi.Size())] = struct{}{}
|
dir[fmt.Sprintf("%s %d", name, fi.Size())] = struct{}{}
|
||||||
assert.Equal(t, r.vfsOpt.FilePerms&os.ModePerm, fi.Mode().Perm())
|
assert.Equal(t, os.FileMode(r.vfsOpt.FilePerms)&os.ModePerm, fi.Mode().Perm())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,5 +376,5 @@ func TestRoot(t *testing.T) {
|
||||||
fi, err := os.Lstat(run.mountPath)
|
fi, err := os.Lstat(run.mountPath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.True(t, fi.IsDir())
|
assert.True(t, fi.IsDir())
|
||||||
assert.Equal(t, run.vfsOpt.DirPerms&os.ModePerm, fi.Mode().Perm())
|
assert.Equal(t, os.FileMode(run.vfsOpt.DirPerms)&os.ModePerm, fi.Mode().Perm())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user