diff --git a/lib/model/rwfolder.go b/lib/model/rwfolder.go index 8276a5ac..ab9a4372 100644 --- a/lib/model/rwfolder.go +++ b/lib/model/rwfolder.go @@ -53,8 +53,9 @@ type copyBlocksState struct { const retainBits = os.ModeSetgid | os.ModeSetuid | os.ModeSticky var ( - activity = newDeviceActivity() - errNoDevice = errors.New("peers who had this file went away, or the file has changed while syncing. will retry later") + activity = newDeviceActivity() + errNoDevice = errors.New("peers who had this file went away, or the file has changed while syncing. will retry later") + errSymlinksUnsupported = errors.New("symlinks not supported") ) const ( @@ -1759,6 +1760,9 @@ func fileValid(file db.FileIntf) error { // We don't care about file validity if we're not supposed to have it return nil + case runtime.GOOS == "windows" && file.IsSymlink(): + return errSymlinksUnsupported + case runtime.GOOS == "windows" && windowsInvalidFilename(file.FileName()): return errInvalidFilename } diff --git a/lib/scanner/walk.go b/lib/scanner/walk.go index 8925d527..dded1e87 100644 --- a/lib/scanner/walk.go +++ b/lib/scanner/walk.go @@ -373,6 +373,12 @@ func (w *walker) walkDir(relPath string, info os.FileInfo, dchan chan protocol.F // walkSymlink returns nil or an error, if the error is of the nature that // it should stop the entire walk. func (w *walker) walkSymlink(absPath, relPath string, dchan chan protocol.FileInfo) error { + // Symlinks are not supported on Windows. We ignore instead of returning + // an error. + if runtime.GOOS == "windows" { + return nil + } + // We always rehash symlinks as they have no modtime or // permissions. We check if they point to the old target by // checking that their existing blocks match with the blocks in diff --git a/lib/scanner/walk_test.go b/lib/scanner/walk_test.go index cfcaa74d..a65b6806 100644 --- a/lib/scanner/walk_test.go +++ b/lib/scanner/walk_test.go @@ -280,7 +280,7 @@ func TestIssue1507(t *testing.T) { fn("", nil, protocol.ErrClosed) } -func TestWalkSymlink(t *testing.T) { +func TestWalkSymlinkUnix(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("skipping unsupported symlink test") return @@ -323,6 +323,45 @@ func TestWalkSymlink(t *testing.T) { } } +func TestWalkSymlinkWindows(t *testing.T) { + if runtime.GOOS != "windows" { + t.Skip("skipping unsupported symlink test") + } + + // Create a folder with a symlink in it + + os.RemoveAll("_symlinks") + defer os.RemoveAll("_symlinks") + + os.Mkdir("_symlinks", 0755) + if err := os.Symlink("destination", "_symlinks/link"); err != nil { + // Probably we require permissions we don't have. + t.Skip(err) + } + + // Scan it + + fchan, err := Walk(Config{ + Dir: "_symlinks", + BlockSize: 128 * 1024, + }) + + if err != nil { + t.Fatal(err) + } + + var files []protocol.FileInfo + for f := range fchan { + files = append(files, f) + } + + // Verify that we got zero symlinks + + if len(files) != 0 { + t.Errorf("expected zero symlinks, not %d", len(files)) + } +} + func walkDir(dir string) ([]protocol.FileInfo, error) { fchan, err := Walk(Config{ Dir: dir,