diff --git a/backend/alias/alias.go b/backend/alias/alias.go index df41019dd..b90037fb6 100644 --- a/backend/alias/alias.go +++ b/backend/alias/alias.go @@ -2,13 +2,12 @@ package alias import ( "errors" - "path" - "path/filepath" "strings" "github.com/ncw/rclone/fs" "github.com/ncw/rclone/fs/config/configmap" "github.com/ncw/rclone/fs/config/configstruct" + "github.com/ncw/rclone/fs/fspath" ) // Register with Fs @@ -47,14 +46,9 @@ func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) { if strings.HasPrefix(opt.Remote, name+":") { return nil, errors.New("can't point alias remote at itself - check the value of the remote setting") } - _, configName, fsPath, err := fs.ParseRemote(opt.Remote) + fsInfo, configName, fsPath, config, err := fs.ConfigFs(opt.Remote) if err != nil { return nil, err } - if configName == "local" { - root = filepath.Join(fsPath, root) - return fs.NewFs(root) - } - root = path.Join(fsPath, filepath.ToSlash(root)) - return fs.NewFs(configName + ":" + root) + return fsInfo.NewFs(configName, fspath.JoinRootPath(fsPath, root), config) } diff --git a/backend/cache/cache.go b/backend/cache/cache.go index 7ce38d7ea..b613df377 100644 --- a/backend/cache/cache.go +++ b/backend/cache/cache.go @@ -24,6 +24,7 @@ import ( "github.com/ncw/rclone/fs/config/configmap" "github.com/ncw/rclone/fs/config/configstruct" "github.com/ncw/rclone/fs/config/obscure" + "github.com/ncw/rclone/fs/fspath" "github.com/ncw/rclone/fs/hash" "github.com/ncw/rclone/fs/rc" "github.com/ncw/rclone/fs/walk" @@ -363,7 +364,7 @@ func NewFs(name, rootPath string, m configmap.Mapper) (fs.Fs, error) { return nil, errors.Wrapf(err, "failed to parse remote %q to wrap", opt.Remote) } - remotePath := path.Join(wPath, rootPath) + remotePath := fspath.JoinRootPath(wPath, rootPath) wrappedFs, wrapErr := wInfo.NewFs(wName, remotePath, wConfig) if wrapErr != nil && wrapErr != fs.ErrorIsFile { return nil, errors.Wrapf(wrapErr, "failed to make remote %s:%s to wrap", wName, remotePath) diff --git a/backend/crypt/crypt.go b/backend/crypt/crypt.go index 363d153f4..23fe1c9c0 100644 --- a/backend/crypt/crypt.go +++ b/backend/crypt/crypt.go @@ -4,7 +4,6 @@ package crypt import ( "fmt" "io" - "path" "strings" "time" @@ -13,6 +12,7 @@ import ( "github.com/ncw/rclone/fs/config/configmap" "github.com/ncw/rclone/fs/config/configstruct" "github.com/ncw/rclone/fs/config/obscure" + "github.com/ncw/rclone/fs/fspath" "github.com/ncw/rclone/fs/hash" "github.com/pkg/errors" ) @@ -143,11 +143,11 @@ func NewFs(name, rpath string, m configmap.Mapper) (fs.Fs, error) { return nil, errors.Wrapf(err, "failed to parse remote %q to wrap", remote) } // Look for a file first - remotePath := path.Join(wPath, cipher.EncryptFileName(rpath)) + remotePath := fspath.JoinRootPath(wPath, cipher.EncryptFileName(rpath)) wrappedFs, err := wInfo.NewFs(wName, remotePath, wConfig) // if that didn't produce a file, look for a directory if err != fs.ErrorIsFile { - remotePath = path.Join(wPath, cipher.EncryptDirName(rpath)) + remotePath = fspath.JoinRootPath(wPath, cipher.EncryptDirName(rpath)) wrappedFs, err = wInfo.NewFs(wName, remotePath, wConfig) } if err != fs.ErrorIsFile && err != nil { diff --git a/fs/fspath/path.go b/fs/fspath/path.go index baa89bbd2..42f3bcd44 100644 --- a/fs/fspath/path.go +++ b/fs/fspath/path.go @@ -5,6 +5,7 @@ import ( "path" "path/filepath" "regexp" + "strings" "github.com/ncw/rclone/fs/driveletter" ) @@ -48,3 +49,19 @@ func Split(remote string) (parent string, leaf string) { parent, leaf = path.Split(remotePath) return remoteName + parent, leaf } + +// JoinRootPath joins any number of path elements into a single path, adding a +// separating slash if necessary. The result is Cleaned; in particular, +// all empty strings are ignored. +// If the first non empty element has a leading "//" this is preserved. +func JoinRootPath(elem ...string) string { + for i, e := range elem { + if e != "" { + if strings.HasPrefix(e, "//") { + return "/" + path.Clean(strings.Join(elem[i:], "/")) + } + return path.Clean(strings.Join(elem[i:], "/")) + } + } + return "" +} diff --git a/fs/fspath/path_test.go b/fs/fspath/path_test.go index d5b41a473..f900d62be 100644 --- a/fs/fspath/path_test.go +++ b/fs/fspath/path_test.go @@ -58,3 +58,32 @@ func TestSplit(t *testing.T) { assert.Equal(t, test.remote, gotParent+gotLeaf, fmt.Sprintf("%s: %q + %q != %q", test.remote, gotParent, gotLeaf, test.remote)) } } +func TestJoinRootPath(t *testing.T) { + for _, test := range []struct { + elements []string + want string + }{ + {nil, ""}, + {[]string{""}, ""}, + {[]string{"/"}, "/"}, + {[]string{"/", "/"}, "/"}, + {[]string{"/", "//"}, "/"}, + {[]string{"/root", ""}, "/root"}, + {[]string{"/root", "/"}, "/root"}, + {[]string{"/root", "//"}, "/root"}, + {[]string{"/a/b"}, "/a/b"}, + {[]string{"//", "/"}, "//"}, + {[]string{"//server", "path"}, "//server/path"}, + {[]string{"//server/sub", "path"}, "//server/sub/path"}, + {[]string{"//server", "//path"}, "//server/path"}, + {[]string{"//server/sub", "//path"}, "//server/sub/path"}, + {[]string{"", "//", "/"}, "//"}, + {[]string{"", "//server", "path"}, "//server/path"}, + {[]string{"", "//server/sub", "path"}, "//server/sub/path"}, + {[]string{"", "//server", "//path"}, "//server/path"}, + {[]string{"", "//server/sub", "//path"}, "//server/sub/path"}, + } { + got := JoinRootPath(test.elements...) + assert.Equal(t, test.want, got) + } +}