From c26dc381c274b1eacf717e44e0f81d00028e1a8c Mon Sep 17 00:00:00 2001 From: Matthieu Gallien Date: Wed, 22 Nov 2023 12:10:18 +0100 Subject: [PATCH] maintain lock state if unlock happens during sync currently unlock can happen during the sync in that case, it may be possible that the propagator will lose the lock state changes and override them when updating teh etag after a file has been uploaded detect that case and ensure we keep consistent state about files Signed-off-by: Matthieu Gallien --- src/libsync/bulkpropagatorjob.cpp | 6 ++++++ src/libsync/propagateupload.cpp | 7 +++++++ src/libsync/propagateuploadng.cpp | 8 +++++++- src/libsync/propagateuploadv1.cpp | 6 ++++++ src/libsync/syncfileitem.cpp | 11 +++++++++++ src/libsync/syncfileitem.h | 2 ++ 6 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/libsync/bulkpropagatorjob.cpp b/src/libsync/bulkpropagatorjob.cpp index 08b3311f18eb1..6d83210f08839 100644 --- a/src/libsync/bulkpropagatorjob.cpp +++ b/src/libsync/bulkpropagatorjob.cpp @@ -398,6 +398,12 @@ void BulkPropagatorJob::slotPutFinishedOneFile(const BulkUploadItem &singleFile, // the file id should only be empty for new files up- or downloaded computeFileId(singleFile._item, fileReply); + if (SyncJournalFileRecord oldRecord; propagator()->_journal->getFileRecord(singleFile._item->destination(), &oldRecord) && oldRecord.isValid()) { + if (oldRecord._etag != singleFile._item->_etag) { + singleFile._item->updateLockStateFromDbRecord(oldRecord); + } + } + singleFile._item->_etag = etag; singleFile._item->_fileId = getHeaderFromJsonReply(fileReply, "fileid"); singleFile._item->_remotePerm = RemotePermissions::fromServerString(getHeaderFromJsonReply(fileReply, "permissions")); diff --git a/src/libsync/propagateupload.cpp b/src/libsync/propagateupload.cpp index ca08042eeaf20..2a7a7bbaabc89 100644 --- a/src/libsync/propagateupload.cpp +++ b/src/libsync/propagateupload.cpp @@ -152,6 +152,13 @@ bool PollJob::finished() if (status == QLatin1String("finished")) { _item->_status = SyncFileItem::Success; _item->_fileId = json["fileId"].toString().toUtf8(); + + if (SyncJournalFileRecord oldRecord; _journal->getFileRecord(_item->destination(), &oldRecord) && oldRecord.isValid()) { + if (oldRecord._etag != _item->_etag) { + _item->updateLockStateFromDbRecord(oldRecord); + } + } + _item->_etag = parseEtag(json["ETag"].toString().toUtf8()); } else { // error _item->_status = classifyError(QNetworkReply::UnknownContentError, _item->_httpErrorCode); diff --git a/src/libsync/propagateuploadng.cpp b/src/libsync/propagateuploadng.cpp index 4642d857b6929..8be463ecd21c9 100644 --- a/src/libsync/propagateuploadng.cpp +++ b/src/libsync/propagateuploadng.cpp @@ -528,8 +528,14 @@ void PropagateUploadFileNG::slotMoveJobFinished() _item->_fileId = fid; } + if (SyncJournalFileRecord oldRecord; propagator()->_journal->getFileRecord(_item->destination(), &oldRecord) && oldRecord.isValid()) { + if (oldRecord._etag != _item->_etag) { + _item->updateLockStateFromDbRecord(oldRecord); + } + } + _item->_etag = getEtagFromReply(job->reply()); - ; + if (_item->_etag.isEmpty()) { qCWarning(lcPropagateUploadNG) << "Server did not return an ETAG" << _item->_file; abortWithError(SyncFileItem::NormalError, tr("Missing ETag from server")); diff --git a/src/libsync/propagateuploadv1.cpp b/src/libsync/propagateuploadv1.cpp index c51fdd3bee7a3..33cd8892d7335 100644 --- a/src/libsync/propagateuploadv1.cpp +++ b/src/libsync/propagateuploadv1.cpp @@ -323,6 +323,12 @@ void PropagateUploadFileV1::slotPutFinished() _item->_fileId = fid; } + if (SyncJournalFileRecord oldRecord; propagator()->_journal->getFileRecord(_item->destination(), &oldRecord) && oldRecord.isValid()) { + if (oldRecord._etag != _item->_etag) { + _item->updateLockStateFromDbRecord(oldRecord); + } + } + _item->_etag = etag; if (job->reply()->rawHeader("X-OC-MTime") != "accepted") { diff --git a/src/libsync/syncfileitem.cpp b/src/libsync/syncfileitem.cpp index 29be0b35f26ff..0076bcad0c39b 100644 --- a/src/libsync/syncfileitem.cpp +++ b/src/libsync/syncfileitem.cpp @@ -218,4 +218,15 @@ SyncFileItemPtr SyncFileItem::fromProperties(const QString &filePath, const QMap return item; } +void SyncFileItem::updateLockStateFromDbRecord(const SyncJournalFileRecord &dbRecord) +{ + _locked = dbRecord._lockstate._locked ? LockStatus::LockedItem : LockStatus::UnlockedItem; + _lockOwnerId = dbRecord._lockstate._lockOwnerId; + _lockOwnerDisplayName = dbRecord._lockstate._lockOwnerDisplayName; + _lockOwnerType = static_cast(dbRecord._lockstate._lockOwnerType); + _lockEditorApp = dbRecord._lockstate._lockEditorApp; + _lockTime = dbRecord._lockstate._lockTime; + _lockTimeout = dbRecord._lockstate._lockTimeout; +} + } diff --git a/src/libsync/syncfileitem.h b/src/libsync/syncfileitem.h index eb263f3424bfc..399546dcd0459 100644 --- a/src/libsync/syncfileitem.h +++ b/src/libsync/syncfileitem.h @@ -236,6 +236,8 @@ class OWNCLOUDSYNC_EXPORT SyncFileItem [[nodiscard]] bool isEncrypted() const { return _e2eEncryptionStatus != EncryptionStatus::NotEncrypted; } + void updateLockStateFromDbRecord(const SyncJournalFileRecord &dbRecord); + // Variables useful for everybody /** The syncfolder-relative filesystem path that the operation is about