Browse Source

Merge pull request #5188 from nextcloud/bugfix/properlyUpdateMetadata

check that we update local file mtime on changes from server
Matthieu Gallien 3 years ago
parent
commit
6d5db8fd95

+ 1 - 1
src/libsync/discovery.cpp

@@ -1871,7 +1871,7 @@ bool ProcessDirectoryJob::isVfsWithSuffix() const
 void ProcessDirectoryJob::computePinState(PinState parentState)
 {
     _pinState = parentState;
-    if (_queryLocal != ParentDontExist) {
+    if (_queryLocal != ParentDontExist && QFileInfo::exists(_discoveryData->_localDir + _currentFolder._local)) {
         if (auto state = _discoveryData->_syncOptions._vfs->pinState(_currentFolder._local)) // ouch! pin local or original?
             _pinState = *state;
     }

+ 1 - 1
src/libsync/propagateremotemove.cpp

@@ -251,7 +251,7 @@ void PropagateRemoteMove::finalize()
         return;
     }
     auto &vfs = propagator()->syncOptions()._vfs;
-    auto pinState = vfs->pinState(_item->_originalFile);
+    auto pinState = vfs->pinState(_item->_renameTarget);
 
     const auto targetFile = propagator()->fullLocalPath(_item->_renameTarget);
 

+ 12 - 9
src/libsync/propagatorjobs.cpp

@@ -222,11 +222,19 @@ void PropagateLocalRename::start()
     if (propagator()->_abortRequested)
         return;
 
+    auto &vfs = propagator()->syncOptions()._vfs;
     const auto previousNameInDb = propagator()->adjustRenamedPath(_item->_file);
     const auto existingFile = propagator()->fullLocalPath(propagator()->adjustRenamedPath(_item->_file));
     const auto targetFile = propagator()->fullLocalPath(_item->_renameTarget);
 
     const auto fileAlreadyMoved = !QFileInfo::exists(propagator()->fullLocalPath(_item->_originalFile));
+    auto pinState = OCC::PinState::Unspecified;
+    if (!fileAlreadyMoved) {
+        auto pinStateResult = vfs->pinState(propagator()->adjustRenamedPath(_item->_file));
+        if (pinStateResult) {
+            pinState = pinStateResult.get();
+        }
+    }
 
     // if the file is a file underneath a moved dir, the _item->file is equal
     // to _item->renameTarget and the file is not moved as a result.
@@ -269,10 +277,10 @@ void PropagateLocalRename::start()
         return;
     }
 
-    auto &vfs = propagator()->syncOptions()._vfs;
-    auto pinState = vfs->pinState(_item->_originalFile);
-    if (!vfs->setPinState(_item->_originalFile, PinState::Inherited)) {
-        qCWarning(lcPropagateLocalRename) << "Could not set pin state of" << _item->_originalFile << "to inherited";
+    if (pinState != OCC::PinState::Unspecified && !vfs->setPinState(_item->_renameTarget, pinState)) {
+        qCWarning(lcPropagateLocalRename) << "Could not set pin state of" << _item->_renameTarget << "to old value" << pinState;
+        done(SyncFileItem::NormalError, tr("Error setting pin state"));
+        return;
     }
 
     const auto oldFile = _item->_file;
@@ -331,11 +339,6 @@ void PropagateLocalRename::start()
             return;
         }
     }
-    if (pinState && *pinState != PinState::Inherited
-        && !vfs->setPinState(_item->_renameTarget, *pinState)) {
-        done(SyncFileItem::NormalError, tr("Error setting pin state"));
-        return;
-    }
 
     propagator()->_journal->commit("localRename");
 

+ 7 - 0
src/libsync/syncengine.cpp

@@ -377,6 +377,13 @@ void OCC::SyncEngine::slotItemDiscovered(const OCC::SyncFileItemPtr &item)
                     emit itemCompleted(item);
                     return;
                 }
+            } else {
+                if (!FileSystem::setModTime(filePath, item->_modtime)) {
+                    item->_instruction = CSYNC_INSTRUCTION_ERROR;
+                    item->_errorString = tr("Could not update file metadata: %1").arg(filePath);
+                    emit itemCompleted(item);
+                    return;
+                }
             }
 
             // Updating the db happens on success

+ 1 - 1
test/syncenginetestutils.cpp

@@ -1209,7 +1209,7 @@ void FakeFolder::fromDisk(QDir &dir, FileInfo &templateFi)
                 continue;
             }
             char contentChar = content.at(0);
-            templateFi.children.insert(diskChild.fileName(), FileInfo { diskChild.fileName(), diskChild.size(), contentChar });
+            templateFi.children.insert(diskChild.fileName(), FileInfo{diskChild.fileName(), diskChild.size(), contentChar, diskChild.lastModified()});
         }
     }
 }

+ 1 - 0
test/syncenginetestutils.h

@@ -117,6 +117,7 @@ public:
     FileInfo(const QString &name) : name{name} { }
     FileInfo(const QString &name, qint64 size) : name{name}, isDir{false}, size{size} { }
     FileInfo(const QString &name, qint64 size, char contentChar) : name{name}, isDir{false}, size{size}, contentChar{contentChar} { }
+    FileInfo(const QString &name, qint64 size, char contentChar, QDateTime mtime) : name{name}, isDir{false}, lastModified(mtime), size{size}, contentChar{contentChar} { }
     FileInfo(const QString &name, const std::initializer_list<FileInfo> &children);
 
     void addChild(const FileInfo &info);

+ 39 - 0
test/testsyncengine.cpp

@@ -1243,6 +1243,45 @@ private slots:
         auto expectedState = fakeFolder.currentLocalState();
         QCOMPARE(fakeFolder.currentRemoteState(), expectedState);
     }
+
+    void testServerUpdatingMTimeShouldNotCreateConflicts()
+    {
+        constexpr auto testFile = "test.txt";
+        constexpr auto CURRENT_MTIME = 1646057277;
+
+        FakeFolder fakeFolder{ FileInfo{} };
+
+        fakeFolder.remoteModifier().insert(testFile);
+        fakeFolder.remoteModifier().setModTimeKeepEtag(testFile, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME - 2));
+
+        fakeFolder.syncEngine().setLocalDiscoveryOptions(OCC::LocalDiscoveryStyle::DatabaseAndFilesystem);
+        QVERIFY(fakeFolder.syncOnce());
+        QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
+        QCOMPARE(printDbData(fakeFolder.dbState()), printDbData(fakeFolder.currentRemoteState()));
+        const auto fileFirstSync = fakeFolder.currentLocalState().find(testFile);
+        QVERIFY(fileFirstSync);
+        QCOMPARE(fileFirstSync->lastModified.toSecsSinceEpoch(), CURRENT_MTIME - 2);
+
+        fakeFolder.remoteModifier().setModTimeKeepEtag(testFile, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME - 1));
+
+        fakeFolder.syncEngine().setLocalDiscoveryOptions(OCC::LocalDiscoveryStyle::FilesystemOnly);
+        QVERIFY(fakeFolder.syncOnce());
+        QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
+        QCOMPARE(printDbData(fakeFolder.dbState()), printDbData(fakeFolder.currentRemoteState()));
+        const auto fileSecondSync = fakeFolder.currentLocalState().find(testFile);
+        QVERIFY(fileSecondSync);
+        QCOMPARE(fileSecondSync->lastModified.toSecsSinceEpoch(), CURRENT_MTIME - 1);
+
+        fakeFolder.remoteModifier().setModTime(testFile, QDateTime::fromSecsSinceEpoch(CURRENT_MTIME));
+
+        fakeFolder.syncEngine().setLocalDiscoveryOptions(OCC::LocalDiscoveryStyle::FilesystemOnly);
+        QVERIFY(fakeFolder.syncOnce());
+        QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
+        QCOMPARE(printDbData(fakeFolder.dbState()), printDbData(fakeFolder.currentRemoteState()));
+        const auto fileThirdSync = fakeFolder.currentLocalState().find(testFile);
+        QVERIFY(fileThirdSync);
+        QCOMPARE(fileThirdSync->lastModified.toSecsSinceEpoch(), CURRENT_MTIME);
+    }
 };
 
 QTEST_GUILESS_MAIN(TestSyncEngine)