With this change we emulate a case sensitive filesystem on top of insensitive filesystems. This means we correctly pick up case-only renames and throw a case conflict error when there would be multiple files differing only in case. This safety check has a small performance hit (about 20% more filesystem operations when scanning for changes). The new advanced folder option `caseSensitiveFS` can be used to disable the safety checks, retaining the previous behavior on systems known to be fully case sensitive. Co-authored-by: Jakob Borg <jakob@kastelo.net>
This commit is contained in:
committed by
Jakob Borg
co-authored by
Jakob Borg
parent
21dd9d6b43
commit
932d8c69de
@@ -22,7 +22,6 @@ import (
|
||||
"github.com/d4l3k/messagediff"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/fs"
|
||||
"github.com/syncthing/syncthing/lib/osutil"
|
||||
"github.com/syncthing/syncthing/lib/protocol"
|
||||
)
|
||||
|
||||
@@ -129,13 +128,6 @@ func TestDeviceConfig(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
// The cachedFilesystem will have been resolved to an absolute path,
|
||||
// depending on where the tests are running. Zero it out so we don't
|
||||
// fail based on that.
|
||||
for i := range cfg.Folders {
|
||||
cfg.Folders[i].cachedFilesystem = nil
|
||||
}
|
||||
|
||||
expectedDevices := []DeviceConfiguration{
|
||||
{
|
||||
DeviceID: device1,
|
||||
@@ -465,6 +457,7 @@ func TestFolderCheckPath(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
testFs := fs.NewFilesystem(fs.FilesystemTypeBasic, n)
|
||||
|
||||
err = os.MkdirAll(filepath.Join(n, "dir", ".stfolder"), os.FileMode(0777))
|
||||
if err != nil {
|
||||
@@ -489,7 +482,7 @@ func TestFolderCheckPath(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
err = osutil.DebugSymlinkForTestsOnly(filepath.Join(n, "dir"), filepath.Join(n, "link"))
|
||||
err = fs.DebugSymlinkForTestsOnly(testFs, testFs, "dir", "link")
|
||||
if err == nil {
|
||||
t.Log("running with symlink check")
|
||||
testcases = append(testcases, struct {
|
||||
|
||||
@@ -61,8 +61,8 @@ type FolderConfiguration struct {
|
||||
DisableFsync bool `xml:"disableFsync" json:"disableFsync"`
|
||||
BlockPullOrder BlockPullOrder `xml:"blockPullOrder" json:"blockPullOrder"`
|
||||
CopyRangeMethod fs.CopyRangeMethod `xml:"copyRangeMethod" json:"copyRangeMethod" default:"standard"`
|
||||
CaseSensitiveFS bool `xml:"caseSensitiveFS" json:"caseSensitiveFS"`
|
||||
|
||||
cachedFilesystem fs.Filesystem
|
||||
cachedModTimeWindow time.Duration
|
||||
|
||||
DeprecatedReadOnly bool `xml:"ro,attr,omitempty" json:"-"`
|
||||
@@ -101,11 +101,11 @@ func (f FolderConfiguration) Copy() FolderConfiguration {
|
||||
func (f FolderConfiguration) Filesystem() fs.Filesystem {
|
||||
// This is intentionally not a pointer method, because things like
|
||||
// cfg.Folders["default"].Filesystem() should be valid.
|
||||
if f.cachedFilesystem == nil {
|
||||
l.Infoln("bug: uncached filesystem call (should only happen in tests)")
|
||||
return fs.NewFilesystem(f.FilesystemType, f.Path)
|
||||
filesystem := fs.NewFilesystem(f.FilesystemType, f.Path)
|
||||
if !f.CaseSensitiveFS {
|
||||
filesystem = fs.NewCaseFilesystem(filesystem)
|
||||
}
|
||||
return f.cachedFilesystem
|
||||
return filesystem
|
||||
}
|
||||
|
||||
func (f FolderConfiguration) ModTimeWindow() time.Duration {
|
||||
@@ -210,8 +210,6 @@ func (f *FolderConfiguration) DeviceIDs() []protocol.DeviceID {
|
||||
}
|
||||
|
||||
func (f *FolderConfiguration) prepare() {
|
||||
f.cachedFilesystem = fs.NewFilesystem(f.FilesystemType, f.Path)
|
||||
|
||||
if f.RescanIntervalS > MaxRescanIntervalS {
|
||||
f.RescanIntervalS = MaxRescanIntervalS
|
||||
} else if f.RescanIntervalS < 0 {
|
||||
@@ -263,7 +261,6 @@ func (f FolderConfiguration) RequiresRestartOnly() FolderConfiguration {
|
||||
|
||||
// Manual handling for things that are not taken care of by the tag
|
||||
// copier, yet should not cause a restart.
|
||||
copy.cachedFilesystem = nil
|
||||
|
||||
blank := FolderConfiguration{}
|
||||
util.CopyMatchingTag(&blank, ©, "restart", func(v string) bool {
|
||||
|
||||
Reference in New Issue
Block a user