From cca818ea6614c5e39232f7f8bcc76dcda9b3fe88 Mon Sep 17 00:00:00 2001 From: Jacob Howard Date: Fri, 20 Jul 2018 18:07:01 +0300 Subject: [PATCH] Fix for character incompatibility corner case on Windows. We generally rely on system calls rejecting invalid path names so that we can avoid checking every path for invalid characters, but backslashes on Windows can be problematic if synchronizing against a POSIX system where a directory at the same level as the invalid filename has a name that is the prefix (pre-'\' string) of the invalid filename. This commit adds an explicit check for this case with negligible overhead. --- pkg/sync/transition.go | 37 ++++++++++++++++++++++++++++++++++ pkg/sync/transition_posix.go | 7 +++++++ pkg/sync/transition_windows.go | 9 +++++++++ 3 files changed, 53 insertions(+) create mode 100644 pkg/sync/transition_posix.go create mode 100644 pkg/sync/transition_windows.go diff --git a/pkg/sync/transition.go b/pkg/sync/transition.go index b2f960fc..4c128ef1 100644 --- a/pkg/sync/transition.go +++ b/pkg/sync/transition.go @@ -190,6 +190,11 @@ func (t *transitioner) ensureNotExists(path string) error { } func (t *transitioner) removeFile(path string, target *Entry) error { + // Watch for special characters. + if pathContainsInvalidCharacters(path) { + return errors.New("path contains invalid characters") + } + // Ensure that the existing entry hasn't been modified from what we're // expecting. if _, _, _, err := t.ensureExpectedFile(path, target); err != nil { @@ -201,6 +206,11 @@ func (t *transitioner) removeFile(path string, target *Entry) error { } func (t *transitioner) removeSymlink(path string, target *Entry) error { + // Watch for special characters. + if pathContainsInvalidCharacters(path) { + return errors.New("path contains invalid characters") + } + // Ensure that the existing symlink hasn't been modified from what we're // expecting. if err := t.ensureExpectedSymlink(path, target); err != nil { @@ -212,6 +222,12 @@ func (t *transitioner) removeSymlink(path string, target *Entry) error { } func (t *transitioner) removeDirectory(path string, target *Entry) bool { + // Watch for special characters. + if pathContainsInvalidCharacters(path) { + t.recordProblem(path, errors.New("path contains invalid characters")) + return false + } + // Compute the full path to this directory. fullPath := filepath.Join(t.root, path) @@ -332,6 +348,11 @@ func (t *transitioner) remove(path string, target *Entry) *Entry { } func (t *transitioner) swapFile(path string, oldEntry, newEntry *Entry) error { + // Watch for special characters. + if pathContainsInvalidCharacters(path) { + return errors.New("path contains invalid characters") + } + // Compute the full path to this file. fullPath := filepath.Join(t.root, path) @@ -394,6 +415,11 @@ func (t *transitioner) swapFile(path string, oldEntry, newEntry *Entry) error { } func (t *transitioner) createFile(path string, target *Entry) error { + // Watch for special characters. + if pathContainsInvalidCharacters(path) { + return errors.New("path contains invalid characters") + } + // Ensure that the target path doesn't exist, e.g. due to a case conflict or // modification since the last scan. if err := t.ensureNotExists(path); err != nil { @@ -429,6 +455,11 @@ func (t *transitioner) createFile(path string, target *Entry) error { } func (t *transitioner) createSymlink(path string, target *Entry) error { + // Watch for special characters. + if pathContainsInvalidCharacters(path) { + return errors.New("path contains invalid characters") + } + // Ensure that the target path doesn't exist, e.g. due to a case conflict or // modification since the last scan. if err := t.ensureNotExists(path); err != nil { @@ -445,6 +476,12 @@ func (t *transitioner) createSymlink(path string, target *Entry) error { } func (t *transitioner) createDirectory(path string, target *Entry) *Entry { + // Watch for special characters. + if pathContainsInvalidCharacters(path) { + t.recordProblem(path, errors.New("path contains invalid characters")) + return nil + } + // Ensure that the target path doesn't exist, e.g. due to a case conflict or // modification since the last scan. if err := t.ensureNotExists(path); err != nil { diff --git a/pkg/sync/transition_posix.go b/pkg/sync/transition_posix.go new file mode 100644 index 00000000..b1ff7389 --- /dev/null +++ b/pkg/sync/transition_posix.go @@ -0,0 +1,7 @@ +// +build !windows + +package sync + +func pathContainsInvalidCharacters(path string) bool { + return false +} diff --git a/pkg/sync/transition_windows.go b/pkg/sync/transition_windows.go new file mode 100644 index 00000000..bd9c1b94 --- /dev/null +++ b/pkg/sync/transition_windows.go @@ -0,0 +1,9 @@ +package sync + +import ( + "strings" +) + +func pathContainsInvalidCharacters(path string) bool { + return strings.Contains(path, "\\") +}