From 6e845410d3f180cceab7c448c80d088ced6925ed 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..f014bcd820461 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(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..c513a1bf95a66 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(SyncJournalFileRecord dbRecord); + // Variables useful for everybody /** The syncfolder-relative filesystem path that the operation is about