mirror of
https://github.com/rclone/rclone.git
synced 2025-12-06 00:03:32 +00:00
operations: fix overlapping check on case insensitive file systems
Before this change, the overlapping check could erroneously give this
error on case insensitive file systems:
Failed to sync: destination and parameter to --backup-dir mustn't overlap
The code was fixed and re-worked to be simpler and more reliable.
See: https://forum.rclone.org/t/backup-dir-cannot-be-in-root-even-when-excluded/39844/
This commit is contained in:
@@ -826,17 +826,19 @@ func Same(fdst, fsrc fs.Info) bool {
|
||||
return SameConfig(fdst, fsrc) && strings.Trim(fdst.Root(), "/") == strings.Trim(fsrc.Root(), "/")
|
||||
}
|
||||
|
||||
// fixRoot returns the Root with a trailing / if not empty. It is
|
||||
// aware of case insensitive filesystems.
|
||||
func fixRoot(f fs.Info) string {
|
||||
s := strings.Trim(filepath.ToSlash(f.Root()), "/")
|
||||
// fixRoot returns the Root with a trailing / if not empty.
|
||||
//
|
||||
// It returns a case folded version for case insensitive file systems
|
||||
func fixRoot(f fs.Info) (s string, folded string) {
|
||||
s = strings.Trim(filepath.ToSlash(f.Root()), "/")
|
||||
if s != "" {
|
||||
s += "/"
|
||||
}
|
||||
folded = s
|
||||
if f.Features().CaseInsensitive {
|
||||
s = strings.ToLower(s)
|
||||
folded = strings.ToLower(s)
|
||||
}
|
||||
return s
|
||||
return s, folded
|
||||
}
|
||||
|
||||
// OverlappingFilterCheck returns true if fdst and fsrc point to the same
|
||||
@@ -845,37 +847,28 @@ func OverlappingFilterCheck(ctx context.Context, fdst fs.Fs, fsrc fs.Fs) bool {
|
||||
if !SameConfig(fdst, fsrc) {
|
||||
return false
|
||||
}
|
||||
fdstRoot := fixRoot(fdst)
|
||||
fsrcRoot := fixRoot(fsrc)
|
||||
if strings.HasPrefix(fdstRoot, fsrcRoot) {
|
||||
fdstRoot, fdstRootFolded := fixRoot(fdst)
|
||||
fsrcRoot, fsrcRootFolded := fixRoot(fsrc)
|
||||
if fdstRootFolded == fsrcRootFolded {
|
||||
return true
|
||||
} else if strings.HasPrefix(fdstRootFolded, fsrcRootFolded) {
|
||||
fdstRelative := fdstRoot[len(fsrcRoot):]
|
||||
return filterCheckR(ctx, fdstRelative, 0, fsrc)
|
||||
return filterCheck(ctx, fsrc, fdstRelative)
|
||||
} else if strings.HasPrefix(fsrcRootFolded, fdstRootFolded) {
|
||||
fsrcRelative := fsrcRoot[len(fdstRoot):]
|
||||
return filterCheck(ctx, fdst, fsrcRelative)
|
||||
}
|
||||
return strings.HasPrefix(fsrcRoot, fdstRoot)
|
||||
return false
|
||||
}
|
||||
|
||||
// filterCheckR checks if fdst would be included in the sync
|
||||
func filterCheckR(ctx context.Context, fdstRelative string, pos int, fsrc fs.Fs) bool {
|
||||
include := true
|
||||
// filterCheck checks if dir is included in f
|
||||
func filterCheck(ctx context.Context, f fs.Fs, dir string) bool {
|
||||
fi := filter.GetConfig(ctx)
|
||||
includeDirectory := fi.IncludeDirectory(ctx, fsrc)
|
||||
dirs := strings.SplitAfterN(fdstRelative, "/", pos+2)
|
||||
newPath := ""
|
||||
for i := 0; i <= pos; i++ {
|
||||
newPath += dirs[i]
|
||||
}
|
||||
if !strings.HasSuffix(newPath, "/") {
|
||||
newPath += "/"
|
||||
}
|
||||
if strings.HasPrefix(fdstRelative, newPath) {
|
||||
include, _ = includeDirectory(newPath)
|
||||
if include {
|
||||
if newPath == fdstRelative {
|
||||
return true
|
||||
}
|
||||
pos++
|
||||
include = filterCheckR(ctx, fdstRelative, pos, fsrc)
|
||||
}
|
||||
includeDirectory := fi.IncludeDirectory(ctx, f)
|
||||
include, err := includeDirectory(dir)
|
||||
if err != nil {
|
||||
fs.Errorf(f, "Failed to discover whether directory is included: %v", err)
|
||||
return true
|
||||
}
|
||||
return include
|
||||
}
|
||||
@@ -886,9 +879,9 @@ func SameDir(fdst, fsrc fs.Info) bool {
|
||||
if !SameConfig(fdst, fsrc) {
|
||||
return false
|
||||
}
|
||||
fdstRoot := fixRoot(fdst)
|
||||
fsrcRoot := fixRoot(fsrc)
|
||||
return fdstRoot == fsrcRoot
|
||||
_, fdstRootFolded := fixRoot(fdst)
|
||||
_, fsrcRootFolded := fixRoot(fsrc)
|
||||
return fdstRootFolded == fsrcRootFolded
|
||||
}
|
||||
|
||||
// Retry runs fn up to maxTries times if it returns a retriable error
|
||||
|
||||
Reference in New Issue
Block a user