Browse Source

Discovery win: Fix detection of case-only renames

Previously they were detected as DELETE+NEW because if "a" is renamed to
"A" then QFile::exists("a") will still return true on Windows.
Christian Kamm 7 years ago
parent
commit
93afc2a04b
2 changed files with 29 additions and 3 deletions
  1. 7 3
      src/libsync/discovery.cpp
  2. 22 0
      test/testsyncmove.cpp

+ 7 - 3
src/libsync/discovery.cpp

@@ -807,9 +807,14 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo(
                // Directories and virtual files don't need size/mtime equality
                || localEntry.isDirectory || localEntry.isVirtualFile);
 
+    auto originalPath = QString::fromUtf8(base._path);
     if (isMove) {
-        //  The old file must have been deleted.
-        isMove = !QFile::exists(_discoveryData->_localDir + base._path);
+        // The old file must have been deleted.
+        isMove = !QFile::exists(_discoveryData->_localDir + base._path)
+                // Exception: If the rename changes case only (like "foo" -> "Foo") the
+                // old filename might still point to the same file.
+                || (Utility::fsCasePreserving()
+                    && originalPath.compare(path._local, Qt::CaseInsensitive) == 0);
     }
 
     // Verify the checksum where possible
@@ -819,7 +824,6 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo(
             isMove = item->_checksumHeader == base._checksumHeader;
         }
     }
-    auto originalPath = QString::fromUtf8(base._path);
     if (isMove && _discoveryData->isRenamed(originalPath))
         isMove = false;
 

+ 22 - 0
test/testsyncmove.cpp

@@ -585,6 +585,28 @@ private slots:
         QCOMPARE(counter.nDELETE, 0);
     }
 
+    // These renames can be troublesome on windows
+    void testRenameCaseOnly()
+    {
+        FakeFolder fakeFolder{ FileInfo::A12_B12_C12_S12() };
+        auto &local = fakeFolder.localModifier();
+        auto &remote = fakeFolder.remoteModifier();
+
+        OperationCounter counter;
+        fakeFolder.setServerOverride(counter.functor());
+
+        local.rename("A/a1", "A/A1");
+        remote.rename("A/a2", "A/A2");
+
+        QVERIFY(fakeFolder.syncOnce());
+        QCOMPARE(fakeFolder.currentLocalState(), remote);
+        QCOMPARE(printDbData(fakeFolder.dbState()), printDbData(fakeFolder.currentRemoteState()));
+        QCOMPARE(counter.nGET, 0);
+        QCOMPARE(counter.nPUT, 0);
+        QCOMPARE(counter.nMOVE, 1);
+        QCOMPARE(counter.nDELETE, 0);
+    }
+
     // Check interaction of moves with file type changes
     void testMoveAndTypeChange()
     {