local: don't resolve relative roots to absolute paths - fixes #9510
cleanRootPath used filepath.Abs which prepends the current directory, but the resulting absolute path does not always refer to the same directory as the original relative path - for example when the current directory is shadowed by a mount or has been removed. This made "rclone copy --links . ../dst" fail where "cp -ra . ../dst" succeeds. rclone now cleans the path lexically on non-Windows platforms instead, leaving relative roots relative so the OS resolves them against the live working directory. Windows still makes the path absolute as required for UNC long-path conversion.
This commit is contained in:
+11
-2
@@ -1823,10 +1823,19 @@ func cleanRootPath(s string, noUNC bool, enc encoder.MultiEncoder) string {
|
|||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
s = vol + s
|
s = vol + s
|
||||||
}
|
}
|
||||||
s2, err := filepath.Abs(s)
|
// UNC paths on Windows must be absolute, so make the path absolute
|
||||||
if err == nil {
|
// there. On other platforms filepath.Abs would prepend the current
|
||||||
|
// directory, but the resulting absolute string is not guaranteed to
|
||||||
|
// refer to the same directory as the original relative path - for
|
||||||
|
// example when the current directory is shadowed by a mount or has been
|
||||||
|
// removed - so just clean it lexically instead.
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
if s2, err := filepath.Abs(s); err == nil {
|
||||||
s = s2
|
s = s2
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
s = filepath.Clean(s)
|
||||||
|
}
|
||||||
if !noUNC {
|
if !noUNC {
|
||||||
// Convert to UNC. It does nothing on non windows platforms.
|
// Convert to UNC. It does nothing on non windows platforms.
|
||||||
s = file.UNCPath(s)
|
s = file.UNCPath(s)
|
||||||
|
|||||||
@@ -30,3 +30,29 @@ func TestCleanWindows(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Relative roots must stay relative so the OS resolves them against the
|
||||||
|
// live working directory rather than a canonicalised string that may no
|
||||||
|
// longer refer to the same directory (#9510).
|
||||||
|
var testsRelative = [][2]string{
|
||||||
|
{".", "."},
|
||||||
|
{"./", "."},
|
||||||
|
{"sub/dir", "sub/dir"},
|
||||||
|
{"sub/dir/", "sub/dir"},
|
||||||
|
{"./sub/dir", "sub/dir"},
|
||||||
|
{"sub/../dir", "dir"},
|
||||||
|
{"..", ".."},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCleanRootPathRelative(t *testing.T) {
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
t.Skipf("non-windows only")
|
||||||
|
}
|
||||||
|
for _, test := range testsRelative {
|
||||||
|
got := cleanRootPath(test[0], true, encoder.OS)
|
||||||
|
expect := test[1]
|
||||||
|
if got != expect {
|
||||||
|
t.Fatalf("got %q, expected %q", got, expect)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user