lib/fs: Properly handle case insensitive systems (fixes #1787, fixes #2739, fixes #5708)

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:
Simon Frei
2020-07-28 11:15:11 +02:00
committed by Jakob Borg
co-authored by Jakob Borg
parent 21dd9d6b43
commit 932d8c69de
27 changed files with 1241 additions and 187 deletions
+6 -6
View File
@@ -323,7 +323,7 @@ func pullInvalidIgnored(t *testing.T, ft config.FolderType) {
fc.deleteFile(invDel)
fc.addFile(ign, 0644, protocol.FileInfoTypeFile, contents)
fc.addFile(ignExisting, 0644, protocol.FileInfoTypeFile, contents)
if err := ioutil.WriteFile(filepath.Join(fss.URI(), ignExisting), otherContents, 0644); err != nil {
if err := writeFile(fss, ignExisting, otherContents, 0644); err != nil {
panic(err)
}
@@ -465,12 +465,12 @@ func TestIssue4841(t *testing.T) {
func TestRescanIfHaveInvalidContent(t *testing.T) {
m, fc, fcfg := setupModelWithConnection()
tmpDir := fcfg.Filesystem().URI()
defer cleanupModelAndRemoveDir(m, tmpDir)
tfs := fcfg.Filesystem()
defer cleanupModelAndRemoveDir(m, tfs.URI())
payload := []byte("hello")
must(t, ioutil.WriteFile(filepath.Join(tmpDir, "foo"), payload, 0777))
must(t, writeFile(tfs, "foo", payload, 0777))
received := make(chan []protocol.FileInfo)
fc.mut.Lock()
@@ -511,7 +511,7 @@ func TestRescanIfHaveInvalidContent(t *testing.T) {
payload = []byte("bye")
buf = make([]byte, len(payload))
must(t, ioutil.WriteFile(filepath.Join(tmpDir, "foo"), payload, 0777))
must(t, writeFile(tfs, "foo", payload, 0777))
_, err = m.Request(device1, "default", "foo", int32(len(payload)), 0, f.Blocks[0].Hash, f.Blocks[0].WeakHash, false)
if err == nil {
@@ -1051,7 +1051,7 @@ func TestIgnoreDeleteUnignore(t *testing.T) {
}
fc.mut.Unlock()
if err := ioutil.WriteFile(filepath.Join(fss.URI(), file), contents, 0644); err != nil {
if err := writeFile(fss, file, contents, 0644); err != nil {
panic(err)
}
m.ScanFolders()