Skip to content

Commit 4dd2221

Browse files
authored
Merge pull request #5293 from nextcloud/bugfix/do-not-generate-conflict-when-locking-and-unlocking
Update file's metadata in the local database when the etag changes while file remains unchanged. Fix subsequent conflict when locking and unlocking.
2 parents d2d9de7 + 50ffc73 commit 4dd2221

3 files changed

Lines changed: 69 additions & 3 deletions

File tree

src/libsync/propagatedownload.cpp

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,13 +1106,39 @@ void PropagateDownloadFile::contentChecksumComputed(const QByteArray &checksumTy
11061106
{
11071107
_item->_checksumHeader = makeChecksumHeader(checksumType, checksum);
11081108

1109+
const auto localFilePath = propagator()->fullLocalPath(_item->_file);
1110+
SyncJournalFileRecord record;
1111+
if (_item->_instruction != CSYNC_INSTRUCTION_CONFLICT && FileSystem::fileExists(localFilePath)
1112+
&& (propagator()->_journal->getFileRecord(_item->_file, &record) && record.isValid())
1113+
&& (record._modtime == _item->_modtime && record._etag != _item->_etag)) {
1114+
const auto computeChecksum = new ComputeChecksum(this);
1115+
computeChecksum->setChecksumType(checksumType);
1116+
connect(computeChecksum, &ComputeChecksum::done, this, &PropagateDownloadFile::localFileContentChecksumComputed);
1117+
computeChecksum->start(localFilePath);
1118+
return;
1119+
}
1120+
1121+
finalizeDownload();
1122+
}
1123+
1124+
void PropagateDownloadFile::localFileContentChecksumComputed(const QByteArray &checksumType, const QByteArray &checksum)
1125+
{
1126+
if (_item->_checksumHeader == makeChecksumHeader(checksumType, checksum)) {
1127+
FileSystem::remove(_tmpFile.fileName());
1128+
updateMetadata(false);
1129+
return;
1130+
}
1131+
finalizeDownload();
1132+
}
1133+
1134+
void PropagateDownloadFile::finalizeDownload()
1135+
{
11091136
if (_isEncrypted) {
11101137
if (_downloadEncryptedHelper->decryptFile(_tmpFile)) {
1111-
downloadFinished();
1138+
downloadFinished();
11121139
} else {
1113-
done(SyncFileItem::NormalError, _downloadEncryptedHelper->errorString());
1140+
done(SyncFileItem::NormalError, _downloadEncryptedHelper->errorString());
11141141
}
1115-
11161142
} else {
11171143
downloadFinished();
11181144
}

src/libsync/propagatedownload.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,10 @@ private slots:
230230
void transmissionChecksumValidated(const QByteArray &checksumType, const QByteArray &checksum);
231231
/// Called when the download's checksum computation is done
232232
void contentChecksumComputed(const QByteArray &checksumType, const QByteArray &checksum);
233+
/// Called when the local file's checksum computation is done
234+
void localFileContentChecksumComputed(const QByteArray &checksumType, const QByteArray &checksum);
235+
236+
void finalizeDownload();
233237
void downloadFinished();
234238
/// Called when it's time to update the db metadata
235239
void updateMetadata(bool isConflict);

test/testsyncconflict.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,42 @@ private slots:
599599
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
600600
}
601601

602+
void testEtagChangeFileNotChangedGeneratesNoConflicts()
603+
{
604+
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
605+
ItemCompletedSpy completeSpy(fakeFolder);
606+
607+
fakeFolder.remoteModifier().insert("A/fake_conflict", 'W');
608+
QVERIFY(fakeFolder.syncOnce());
609+
QVERIFY(!itemConflict(completeSpy, "A/fake_conflict"));
610+
611+
completeSpy.clear();
612+
613+
fakeFolder.remoteModifier().setContents("A/fake_conflict", 'W');
614+
fakeFolder.localModifier().setContents("A/fake_conflict", 'W');
615+
616+
QVERIFY(fakeFolder.syncOnce());
617+
QVERIFY(!itemConflict(completeSpy, "A/fake_conflict"));
618+
}
619+
620+
void testEtagChangeFileChangedGeneratesConflicts()
621+
{
622+
FakeFolder fakeFolder{FileInfo::A12_B12_C12_S12()};
623+
ItemCompletedSpy completeSpy(fakeFolder);
624+
625+
fakeFolder.remoteModifier().insert("A/real_conflict", 'W');
626+
QVERIFY(fakeFolder.syncOnce());
627+
QVERIFY(!itemConflict(completeSpy, "A/real_conflict"));
628+
629+
completeSpy.clear();
630+
631+
fakeFolder.remoteModifier().setContents("A/real_conflict", 'W');
632+
fakeFolder.localModifier().setContents("A/real_conflict", 'L');
633+
634+
QVERIFY(fakeFolder.syncOnce());
635+
QVERIFY(itemConflict(completeSpy, "A/real_conflict"));
636+
}
637+
602638
// Test what happens if we remove entries both on the server, and locally
603639
void testRemoveRemove()
604640
{

0 commit comments

Comments
 (0)