From 07aaba8f880e717039e22850d24d4c59e9cfb06d Mon Sep 17 00:00:00 2001 From: Hannah von Reth Date: Fri, 19 Nov 2021 15:31:11 +0100 Subject: [PATCH] Fix crash in PropagateRemoteMkdir Fixes: #9170 --- changelog/unreleased/9170 | 6 ++ src/libsync/propagateremotemkdir.cpp | 84 ++++++++++++---------------- src/libsync/propagateremotemkdir.h | 6 ++ 3 files changed, 49 insertions(+), 47 deletions(-) create mode 100644 changelog/unreleased/9170 diff --git a/changelog/unreleased/9170 b/changelog/unreleased/9170 new file mode 100644 index 00000000000..baf7102acad --- /dev/null +++ b/changelog/unreleased/9170 @@ -0,0 +1,6 @@ +Bugfix: Crash when handling locked files + +We fixed a crash that could occur when trying to add a locked folder to the databse. + + +https://github.com/owncloud/client/issues/9170 diff --git a/src/libsync/propagateremotemkdir.cpp b/src/libsync/propagateremotemkdir.cpp index 199eba652ff..a1d951c57a2 100644 --- a/src/libsync/propagateremotemkdir.cpp +++ b/src/libsync/propagateremotemkdir.cpp @@ -22,8 +22,11 @@ #include #include #include + +using namespace std::chrono_literals; + namespace { -auto UpdateMetaDataRetyTimeOut = std::chrono::seconds(30); +constexpr auto UpdateMetaDataRetyTimeOut = 30s; } namespace OCC { @@ -130,13 +133,12 @@ void PropagateRemoteMkdir::success() { // Never save the etag on first mkdir. // Only fully propagated directories should have the etag set. - auto itemCopy = *_item; - itemCopy._etag.clear(); + auto itemCopy = SyncFileItemPtr::create(*_item); + itemCopy->_etag.clear(); // save the file id already so we can detect rename or remove // also convert to a placeholder for the proper behaviour of the file - Q_ASSERT(thread() == qApp->thread()); - const auto result = propagator()->updateMetadata(itemCopy); + const auto result = propagator()->updateMetadata(*itemCopy); if (!result) { done(SyncFileItem::FatalError, tr("Error writing metadata to the database: %1").arg(result.error())); return; @@ -148,48 +150,7 @@ void PropagateRemoteMkdir::success() // in case the file lock is active. // Retry the conversion for UpdateMetaDataRetyTimeOut // TODO: make update updateMetadata async in general - - // QtConcurrent does not support moves - // use shared_ptr to manage the Result object - using resultType = decltype(result); - using resultTypePtr = decltype(std::shared_ptr()); - - auto *watcher = new QFutureWatcher(this); - connect(watcher, &QFutureWatcherBase::finished, this, [watcher, this] { - const auto *result = watcher->result().get(); - if (*result) { - switch (result->get()) { - case Vfs::ConvertToPlaceholderResult::Ok: - done(SyncFileItem::Success); - return; - case Vfs::ConvertToPlaceholderResult::Locked: - done(SyncFileItem::SoftError, tr("Setting file status failed due to file lock")); - return; - case Vfs::ConvertToPlaceholderResult::Error: - Q_UNREACHABLE(); - } - } - done(SyncFileItem::FatalError, result->error()); - }); - - watcher->setFuture(QtConcurrent::run([p = propagator(), itemCopy] { - // Try to update the meta data with a 30s timeout - const auto start = std::chrono::steady_clock::now(); - while ((std::chrono::steady_clock::now() - start) < UpdateMetaDataRetyTimeOut) { - QThread::sleep(1); - auto result = std::make_shared(p->updateMetadata(itemCopy)); - if (*result) { - if (result->get() == Vfs::ConvertToPlaceholderResult::Locked) { - continue; - } else { - return result; - } - } else { - return result; - } - } - return std::make_shared(Vfs::ConvertToPlaceholderResult::Locked); - })); + retryUpdateMetadata(std::chrono::steady_clock::now(), itemCopy); return; } #else @@ -197,4 +158,33 @@ void PropagateRemoteMkdir::success() #endif done(SyncFileItem::Success); } + +#ifdef Q_OS_WIN +void PropagateRemoteMkdir::retryUpdateMetadata(std::chrono::steady_clock::time_point start, SyncFileItemPtr item) +{ + // Try to update the meta data with a 30s timeout + if ((std::chrono::steady_clock::now() - start) < UpdateMetaDataRetyTimeOut) { + auto result = propagator()->updateMetadata(*item); + if (result) { + switch (*result) { + case Vfs::ConvertToPlaceholderResult::Ok: + done(SyncFileItem::Success); + return; + case Vfs::ConvertToPlaceholderResult::Locked: + // retry in 1s + QTimer::singleShot(1s, this, [start, item, this] { + retryUpdateMetadata(start, item); + }); + return; + case Vfs::ConvertToPlaceholderResult::Error: + Q_UNREACHABLE(); + } + } else { + done(SyncFileItem::FatalError, result.error()); + return; + } + } + done(SyncFileItem::SoftError, tr("Setting file status failed due to file lock")); +}; +#endif } diff --git a/src/libsync/propagateremotemkdir.h b/src/libsync/propagateremotemkdir.h index d1168195008..c75be43e50a 100644 --- a/src/libsync/propagateremotemkdir.h +++ b/src/libsync/propagateremotemkdir.h @@ -52,5 +52,11 @@ private slots: void slotStartMkcolJob(); void slotMkcolJobFinished(); void success(); + +private: +#ifdef Q_OS_WIN + void retryUpdateMetadata(std::chrono::steady_clock::time_point start, SyncFileItemPtr item); + +#endif }; }