From 56d48d341f7fee0cdb55325bec3daab3e04c7967 Mon Sep 17 00:00:00 2001 From: Simon Frei Date: Thu, 10 Sep 2020 08:23:54 +0200 Subject: [PATCH] lib/model: Fix case-only renames on pull (#6978) --- lib/model/folder_sendrecv.go | 28 +++++++++++++++------- lib/model/folder_sendrecv_test.go | 39 +++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/lib/model/folder_sendrecv.go b/lib/model/folder_sendrecv.go index 1f1a7899c..aa07bd72b 100644 --- a/lib/model/folder_sendrecv.go +++ b/lib/model/folder_sendrecv.go @@ -945,16 +945,26 @@ func (f *sendReceiveFolder) renameFile(cur, source, target protocol.FileInfo, sn // Check that the target corresponds to what we have in the DB curTarget, ok := snap.Get(protocol.LocalDeviceID, target.Name) switch stat, serr := f.fs.Lstat(target.Name); { - case serr != nil && fs.IsNotExist(serr): - if !ok || curTarget.IsDeleted() { - break - } - scanChan <- target.Name - err = errModified case serr != nil: - // We can't check whether the file changed as compared to the db, - // do not delete. - err = serr + var caseErr *fs.ErrCaseConflict + switch { + case errors.As(serr, &caseErr): + if caseErr.Real != source.Name { + err = serr + break + } + fallthrough // This is a case only rename + case fs.IsNotExist(serr): + if !ok || curTarget.IsDeleted() { + break + } + scanChan <- target.Name + err = errModified + default: + // We can't check whether the file changed as compared to the db, + // do not delete. + err = serr + } case !ok: // Target appeared from nowhere scanChan <- target.Name diff --git a/lib/model/folder_sendrecv_test.go b/lib/model/folder_sendrecv_test.go index ed2e5c77c..f1e0ec7a4 100644 --- a/lib/model/folder_sendrecv_test.go +++ b/lib/model/folder_sendrecv_test.go @@ -1242,6 +1242,45 @@ func TestPullTempFileCaseConflict(t *testing.T) { } } +func TestPullCaseOnlyRename(t *testing.T) { + m, f := setupSendReceiveFolder() + defer cleanupSRFolder(f, m) + + // tempNameConfl := fs.TempName(confl) + + name := "foo" + if fd, err := f.fs.Create(name); err != nil { + t.Fatal(err) + } else { + if _, err := fd.Write([]byte("data")); err != nil { + t.Fatal(err) + } + fd.Close() + } + + must(t, f.scanSubdirs(nil)) + + cur, ok := m.CurrentFolderFile(f.ID, name) + if !ok { + t.Fatal("file missing") + } + + deleted := cur + deleted.SetDeleted(myID.Short()) + + confl := cur + confl.Name = "Foo" + confl.Version = confl.Version.Update(device1.Short()) + + dbUpdateChan := make(chan dbUpdateJob, 2) + scanChan := make(chan string, 2) + snap := f.fset.Snapshot() + defer snap.Release() + if err := f.renameFile(cur, deleted, confl, snap, dbUpdateChan, scanChan); err != nil { + t.Error(err) + } +} + func cleanupSharedPullerState(s *sharedPullerState) { s.mut.Lock() defer s.mut.Unlock()