backend: unify NewFs path handling for wrapping remotes

Use the same function to join the root paths for the wrapping remotes
alias, cache and crypt.
The new function fspath.JoinRootPath is equivalent to path.Join, but if
the first non empty element starts with "//", this is preserved to allow
Windows network path to be used in these remotes.
This commit is contained in:
Fabian Möller 2018-10-09 13:35:27 +02:00 committed by Nick Craig-Wood
parent 411a6cc472
commit 1a40bceb1d
5 changed files with 54 additions and 13 deletions

View File

@ -2,13 +2,12 @@ package alias
import ( import (
"errors" "errors"
"path"
"path/filepath"
"strings" "strings"
"github.com/ncw/rclone/fs" "github.com/ncw/rclone/fs"
"github.com/ncw/rclone/fs/config/configmap" "github.com/ncw/rclone/fs/config/configmap"
"github.com/ncw/rclone/fs/config/configstruct" "github.com/ncw/rclone/fs/config/configstruct"
"github.com/ncw/rclone/fs/fspath"
) )
// Register with Fs // Register with Fs
@ -47,14 +46,9 @@ func NewFs(name, root string, m configmap.Mapper) (fs.Fs, error) {
if strings.HasPrefix(opt.Remote, name+":") { if strings.HasPrefix(opt.Remote, name+":") {
return nil, errors.New("can't point alias remote at itself - check the value of the remote setting") 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 { if err != nil {
return nil, err return nil, err
} }
if configName == "local" { return fsInfo.NewFs(configName, fspath.JoinRootPath(fsPath, root), config)
root = filepath.Join(fsPath, root)
return fs.NewFs(root)
}
root = path.Join(fsPath, filepath.ToSlash(root))
return fs.NewFs(configName + ":" + root)
} }

View File

@ -24,6 +24,7 @@ import (
"github.com/ncw/rclone/fs/config/configmap" "github.com/ncw/rclone/fs/config/configmap"
"github.com/ncw/rclone/fs/config/configstruct" "github.com/ncw/rclone/fs/config/configstruct"
"github.com/ncw/rclone/fs/config/obscure" "github.com/ncw/rclone/fs/config/obscure"
"github.com/ncw/rclone/fs/fspath"
"github.com/ncw/rclone/fs/hash" "github.com/ncw/rclone/fs/hash"
"github.com/ncw/rclone/fs/rc" "github.com/ncw/rclone/fs/rc"
"github.com/ncw/rclone/fs/walk" "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) 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) wrappedFs, wrapErr := wInfo.NewFs(wName, remotePath, wConfig)
if wrapErr != nil && wrapErr != fs.ErrorIsFile { if wrapErr != nil && wrapErr != fs.ErrorIsFile {
return nil, errors.Wrapf(wrapErr, "failed to make remote %s:%s to wrap", wName, remotePath) return nil, errors.Wrapf(wrapErr, "failed to make remote %s:%s to wrap", wName, remotePath)

View File

@ -4,7 +4,6 @@ package crypt
import ( import (
"fmt" "fmt"
"io" "io"
"path"
"strings" "strings"
"time" "time"
@ -13,6 +12,7 @@ import (
"github.com/ncw/rclone/fs/config/configmap" "github.com/ncw/rclone/fs/config/configmap"
"github.com/ncw/rclone/fs/config/configstruct" "github.com/ncw/rclone/fs/config/configstruct"
"github.com/ncw/rclone/fs/config/obscure" "github.com/ncw/rclone/fs/config/obscure"
"github.com/ncw/rclone/fs/fspath"
"github.com/ncw/rclone/fs/hash" "github.com/ncw/rclone/fs/hash"
"github.com/pkg/errors" "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) return nil, errors.Wrapf(err, "failed to parse remote %q to wrap", remote)
} }
// Look for a file first // 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) wrappedFs, err := wInfo.NewFs(wName, remotePath, wConfig)
// if that didn't produce a file, look for a directory // if that didn't produce a file, look for a directory
if err != fs.ErrorIsFile { 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) wrappedFs, err = wInfo.NewFs(wName, remotePath, wConfig)
} }
if err != fs.ErrorIsFile && err != nil { if err != fs.ErrorIsFile && err != nil {

View File

@ -5,6 +5,7 @@ import (
"path" "path"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings"
"github.com/ncw/rclone/fs/driveletter" "github.com/ncw/rclone/fs/driveletter"
) )
@ -48,3 +49,19 @@ func Split(remote string) (parent string, leaf string) {
parent, leaf = path.Split(remotePath) parent, leaf = path.Split(remotePath)
return remoteName + parent, leaf 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 ""
}

View File

@ -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)) 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)
}
}