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:
@@ -20,7 +20,6 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/ignore"
|
||||
"github.com/syncthing/syncthing/lib/osutil"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/symlinks"
|
||||
"golang.org/x/text/unicode/norm"
|
||||
)
|
||||
|
||||
@@ -374,19 +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 {
|
||||
// If the target is a directory, do NOT descend down there. This will
|
||||
// cause files to get tracked, and removing the symlink will as a result
|
||||
// remove files in their real location.
|
||||
if !symlinks.Supported {
|
||||
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
|
||||
// the index.
|
||||
|
||||
target, targetType, err := symlinks.Read(absPath)
|
||||
target, err := os.Readlink(absPath)
|
||||
if err != nil {
|
||||
l.Debugln("readlink error:", absPath, err)
|
||||
return nil
|
||||
@@ -400,13 +392,13 @@ func (w *walker) walkSymlink(absPath, relPath string, dchan chan protocol.FileIn
|
||||
// - the symlink type (file/dir) was the same
|
||||
// - the target was the same
|
||||
cf, ok := w.CurrentFiler.CurrentFile(relPath)
|
||||
if ok && !cf.IsDeleted() && cf.IsSymlink() && !cf.IsInvalid() && SymlinkTypeEqual(targetType, cf) && cf.SymlinkTarget == target {
|
||||
if ok && !cf.IsDeleted() && cf.IsSymlink() && !cf.IsInvalid() && cf.SymlinkTarget == target {
|
||||
return nil
|
||||
}
|
||||
|
||||
f := protocol.FileInfo{
|
||||
Name: relPath,
|
||||
Type: SymlinkType(targetType),
|
||||
Type: protocol.FileInfoTypeSymlink,
|
||||
Version: cf.Version.Update(w.ShortID),
|
||||
NoPermissions: true, // Symlinks don't have permissions of their own
|
||||
SymlinkTarget: target,
|
||||
@@ -489,38 +481,6 @@ func PermsEqual(a, b uint32) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func SymlinkTypeEqual(disk symlinks.TargetType, f protocol.FileInfo) bool {
|
||||
// If the target is missing, Unix never knows what type of symlink it is
|
||||
// and Windows always knows even if there is no target. Which means that
|
||||
// without this special check a Unix node would be fighting with a Windows
|
||||
// node about whether or not the target is known. Basically, if you don't
|
||||
// know and someone else knows, just accept it. The fact that you don't
|
||||
// know means you are on Unix, and on Unix you don't really care what the
|
||||
// target type is. The moment you do know, and if something doesn't match,
|
||||
// that will propagate through the cluster.
|
||||
switch disk {
|
||||
case symlinks.TargetUnknown:
|
||||
return true
|
||||
case symlinks.TargetDirectory:
|
||||
return f.Type == protocol.FileInfoTypeSymlinkDirectory
|
||||
case symlinks.TargetFile:
|
||||
return f.Type == protocol.FileInfoTypeSymlinkFile
|
||||
}
|
||||
panic("unknown symlink TargetType")
|
||||
}
|
||||
|
||||
func SymlinkType(t symlinks.TargetType) protocol.FileInfoType {
|
||||
switch t {
|
||||
case symlinks.TargetFile:
|
||||
return protocol.FileInfoTypeSymlinkFile
|
||||
case symlinks.TargetDirectory:
|
||||
return protocol.FileInfoTypeSymlinkDirectory
|
||||
case symlinks.TargetUnknown:
|
||||
return protocol.FileInfoTypeSymlinkUnknown
|
||||
}
|
||||
panic("unknown symlink TargetType")
|
||||
}
|
||||
|
||||
// A byteCounter gets bytes added to it via Update() and then provides the
|
||||
// Total() and one minute moving average Rate() in bytes per second.
|
||||
type byteCounter struct {
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"github.com/syncthing/syncthing/lib/ignore"
|
||||
"github.com/syncthing/syncthing/lib/osutil"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
"github.com/syncthing/syncthing/lib/symlinks"
|
||||
"golang.org/x/text/unicode/norm"
|
||||
)
|
||||
|
||||
@@ -282,7 +281,7 @@ func TestIssue1507(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWalkSymlink(t *testing.T) {
|
||||
if !symlinks.Supported {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("skipping unsupported symlink test")
|
||||
return
|
||||
}
|
||||
@@ -293,7 +292,7 @@ func TestWalkSymlink(t *testing.T) {
|
||||
defer os.RemoveAll("_symlinks")
|
||||
|
||||
os.Mkdir("_symlinks", 0755)
|
||||
symlinks.Create("_symlinks/link", "destination", symlinks.TargetUnknown)
|
||||
os.Symlink("destination", "_symlinks/link")
|
||||
|
||||
// Scan it
|
||||
|
||||
@@ -383,34 +382,6 @@ func (l testfileList) String() string {
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func TestSymlinkTypeEqual(t *testing.T) {
|
||||
testcases := []struct {
|
||||
onDiskType symlinks.TargetType
|
||||
fiType protocol.FileInfoType
|
||||
equal bool
|
||||
}{
|
||||
// File is only equal to file
|
||||
{symlinks.TargetFile, protocol.FileInfoTypeSymlinkFile, true},
|
||||
{symlinks.TargetFile, protocol.FileInfoTypeSymlinkDirectory, false},
|
||||
{symlinks.TargetFile, protocol.FileInfoTypeSymlinkUnknown, false},
|
||||
// Directory is only equal to directory
|
||||
{symlinks.TargetDirectory, protocol.FileInfoTypeSymlinkFile, false},
|
||||
{symlinks.TargetDirectory, protocol.FileInfoTypeSymlinkDirectory, true},
|
||||
{symlinks.TargetDirectory, protocol.FileInfoTypeSymlinkUnknown, false},
|
||||
// Unknown is equal to anything
|
||||
{symlinks.TargetUnknown, protocol.FileInfoTypeSymlinkFile, true},
|
||||
{symlinks.TargetUnknown, protocol.FileInfoTypeSymlinkDirectory, true},
|
||||
{symlinks.TargetUnknown, protocol.FileInfoTypeSymlinkUnknown, true},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
res := SymlinkTypeEqual(tc.onDiskType, protocol.FileInfo{Type: tc.fiType})
|
||||
if res != tc.equal {
|
||||
t.Errorf("Incorrect result %v for %v, %v", res, tc.onDiskType, tc.fiType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var initOnce sync.Once
|
||||
|
||||
const (
|
||||
|
||||
Reference in New Issue
Block a user