mirror of
https://github.com/rclone/rclone.git
synced 2026-06-28 18:05:12 -04:00
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:
@@ -1726,9 +1726,18 @@ func cleanRootPath(s string, noUNC bool, enc encoder.MultiEncoder) string {
|
||||
if runtime.GOOS == "windows" {
|
||||
s = vol + s
|
||||
}
|
||||
s2, err := filepath.Abs(s)
|
||||
if err == nil {
|
||||
s = s2
|
||||
// UNC paths on Windows must be absolute, so make the path absolute
|
||||
// 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
|
||||
}
|
||||
} else {
|
||||
s = filepath.Clean(s)
|
||||
}
|
||||
if !noUNC {
|
||||
// Convert to UNC. It does nothing on non windows platforms.
|
||||
|
||||
@@ -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