all: Remove symlink support on Windows, SymlinksEnabled config

After this change,

- Symlinks on Windows are always unsupported. Sorry.

- Symlinks are always enabled on other platforms. They are just a small
  file like anything else. There is no need to special case them. If you
  don't want to sync some symlinks, ignore them.

- The protocol doesn't differentiate between different "types" of
  symlinks. If that distinction ever does become relevant the individual
  devices can figure it out by looking at the destination when they
  create the link.

It's backwards compatible in that all the old symlink types are still
understood to be symlinks, and the new SYMLINK type is equivalent to the
old SYMLINK_UNKNOWN which was always a valid way to do it.

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3962
LGTM: AudriusButkevicius
This commit is contained in:
Jakob Borg
2017-02-07 08:34:24 +00:00
parent 9fda9642d3
commit c4ba580cbb
28 changed files with 227 additions and 707 deletions

View File

@@ -20,7 +20,6 @@ import (
"runtime"
"sort"
"strings"
stdsync "sync"
"time"
"github.com/syncthing/syncthing/lib/config"
@@ -33,7 +32,6 @@ import (
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/scanner"
"github.com/syncthing/syncthing/lib/stats"
"github.com/syncthing/syncthing/lib/symlinks"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/upgrade"
"github.com/syncthing/syncthing/lib/versioner"
@@ -105,7 +103,6 @@ type Model struct {
type folderFactory func(*Model, config.FolderConfiguration, versioner.Versioner, *fs.MtimeFS) service
var (
symlinkWarning = stdsync.Once{}
folderFactories = make(map[config.FolderType]folderFactory, 0)
)
@@ -116,7 +113,6 @@ var (
errFolderMarkerMissing = errors.New("folder marker missing")
errHomeDiskNoSpace = errors.New("home disk has insufficient free space")
errFolderNoSpace = errors.New("folder has insufficient free space")
errUnsupportedSymlink = errors.New("symlink not supported")
errInvalidFilename = errors.New("filename is invalid")
errDeviceUnknown = errors.New("unknown device")
errDevicePaused = errors.New("device is paused")
@@ -1879,9 +1875,8 @@ func (m *Model) internalScanFolderSubdirs(folder string, subDirs []string) error
}
switch {
case !f.IsInvalid() && (ignores.Match(f.Name).IsIgnored() || symlinkInvalid(folder, f)):
// File was valid at last pass but has been ignored or is an
// unsupported symlink. Set invalid bit.
case !f.IsInvalid() && ignores.Match(f.Name).IsIgnored():
// File was valid at last pass but has been ignored. Set invalid bit.
l.Debugln("setting invalid bit on ignored", f)
nf := protocol.FileInfo{
Name: f.Name,
@@ -2490,26 +2485,6 @@ func mapDeviceConfigs(devices []config.DeviceConfiguration) map[protocol.DeviceI
return m
}
func symlinkInvalid(folder string, fi db.FileIntf) bool {
if !symlinks.Supported && fi.IsSymlink() && !fi.IsInvalid() && !fi.IsDeleted() {
symlinkWarning.Do(func() {
l.Warnln("Symlinks are disabled, unsupported or require Administrator privileges. This might cause your folder to appear out of sync.")
})
// Need to type switch for the concrete type to be able to access fields...
var name string
switch fi := fi.(type) {
case protocol.FileInfo:
name = fi.Name
case db.FileInfoTruncated:
name = fi.Name
}
l.Infoln("Unsupported symlink", name, "in folder", folder)
return true
}
return false
}
// Skips `skip` elements and retrieves up to `get` elements from a given slice.
// Returns the resulting slice, plus how much elements are left to skip or
// copy to satisfy the values which were provided, given the slice is not

View File

@@ -359,7 +359,7 @@ func TestSendDownloadProgressMessages(t *testing.T) {
file: protocol.FileInfo{
Name: "state6",
Version: v1,
Type: protocol.FileInfoTypeSymlinkUnknown,
Type: protocol.FileInfoTypeSymlink,
},
mut: sync.NewRWMutex(),
available: []int32{1, 2, 3},

View File

@@ -89,7 +89,7 @@ func TestSymlinkTraversalRead(t *testing.T) {
// Send an update for the symlink, wait for it to sync and be reported back.
contents := []byte("..")
fc.addFile("symlink", 0644, protocol.FileInfoTypeSymlinkDirectory, contents)
fc.addFile("symlink", 0644, protocol.FileInfoTypeSymlink, contents)
fc.sendIndexUpdate()
<-done
@@ -142,7 +142,7 @@ func TestSymlinkTraversalWrite(t *testing.T) {
// Send an update for the symlink, wait for it to sync and be reported back.
contents := []byte("..")
fc.addFile("symlink", 0644, protocol.FileInfoTypeSymlinkDirectory, contents)
fc.addFile("symlink", 0644, protocol.FileInfoTypeSymlink, contents)
fc.sendIndexUpdate()
<-done
@@ -152,7 +152,7 @@ func TestSymlinkTraversalWrite(t *testing.T) {
contents = []byte("testdata testdata\n")
fc.addFile("symlink/testfile", 0644, protocol.FileInfoTypeFile, contents)
fc.addFile("symlink/testdir", 0644, protocol.FileInfoTypeDirectory, contents)
fc.addFile("symlink/testsyml", 0644, protocol.FileInfoTypeSymlinkFile, contents)
fc.addFile("symlink/testsyml", 0644, protocol.FileInfoTypeSymlink, contents)
fc.sendIndexUpdate()
select {
@@ -191,7 +191,7 @@ func TestRequestCreateTmpSymlink(t *testing.T) {
fc.mut.Unlock()
// Send an update for the test file, wait for it to sync and be reported back.
fc.addFile(".syncthing.testlink.tmp", 0644, protocol.FileInfoTypeSymlinkDirectory, []byte(".."))
fc.addFile(".syncthing.testlink.tmp", 0644, protocol.FileInfoTypeSymlink, []byte(".."))
fc.sendIndexUpdate()
select {

View File

@@ -25,7 +25,6 @@ import (
"github.com/syncthing/syncthing/lib/osutil"
"github.com/syncthing/syncthing/lib/protocol"
"github.com/syncthing/syncthing/lib/scanner"
"github.com/syncthing/syncthing/lib/symlinks"
"github.com/syncthing/syncthing/lib/sync"
"github.com/syncthing/syncthing/lib/versioner"
"github.com/syncthing/syncthing/lib/weakhash"
@@ -741,15 +740,10 @@ func (f *sendReceiveFolder) handleSymlink(file protocol.FileInfo) {
}
}
tt := symlinks.TargetFile
if file.IsDirectory() {
tt = symlinks.TargetDirectory
}
// We declare a function that acts on only the path name, so
// we can pass it to InWritableDir.
createLink := func(path string) error {
return symlinks.Create(path, file.SymlinkTarget, tt)
return os.Symlink(file.SymlinkTarget, path)
}
if err = osutil.InWritableDir(createLink, realName); err == nil {
@@ -1765,9 +1759,6 @@ func fileValid(file db.FileIntf) error {
// We don't care about file validity if we're not supposed to have it
return nil
case !symlinks.Supported && file.IsSymlink():
return errUnsupportedSymlink
case runtime.GOOS == "windows" && windowsInvalidFilename(file.FileName()):
return errInvalidFilename
}