Merge pull request #5188 from nextcloud/bugfix/properlyUpdateMetadata

check that we update local file mtime on changes from server
This commit is contained in:
Matthieu Gallien 2022-11-22 18:24:11 +01:00 committed by GitHub
commit 6d5db8fd95
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 62 additions and 12 deletions

View file

@ -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;
}

View file

@ -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);

View file

@ -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");

View file

@ -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

View file

@ -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()});
}
}
}

View file

@ -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);

View file

@ -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)