From: Matthieu Gallien Date: Thu, 17 Nov 2022 13:45:11 +0000 (+0100) Subject: fix behavior of folder rename with deep hierarchy inside it X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~11^2~131^2~3 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=9a2f07d53b8fcf17d313f471e9ec410726bcc9a9;p=nextcloud-desktop.git fix behavior of folder rename with deep hierarchy inside it propagate renaming of parent folders to child recursively Signed-off-by: Matthieu Gallien --- diff --git a/src/libsync/propagatorjobs.cpp b/src/libsync/propagatorjobs.cpp index 8f57eb18d..1013b8027 100644 --- a/src/libsync/propagatorjobs.cpp +++ b/src/libsync/propagatorjobs.cpp @@ -211,16 +211,26 @@ void PropagateLocalMkdir::startLocalMkdir() done(resultStatus); } +PropagateLocalRename::PropagateLocalRename(OwncloudPropagator *propagator, const SyncFileItemPtr &item) + : PropagateItemJob(propagator, item) +{ + qCDebug(lcPropagateLocalRename) << _item->_file << _item->_renameTarget << _item->_originalFile; +} + void PropagateLocalRename::start() { if (propagator()->_abortRequested) return; - QString existingFile = propagator()->fullLocalPath(propagator()->adjustRenamedPath(_item->_file)); - QString targetFile = propagator()->fullLocalPath(_item->_renameTarget); + 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)); // 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. + qCDebug(lcPropagateLocalRename) << _item->_file << _item->_renameTarget << _item->_originalFile << previousNameInDb << (fileAlreadyMoved ? "original file has already moved" : "original file is still there"); if (_item->_file != _item->_renameTarget) { propagator()->reportProgress(*_item, 0); qCDebug(lcPropagateLocalRename) << "MOVE " << existingFile << " => " << targetFile; @@ -249,15 +259,37 @@ void PropagateLocalRename::start() } SyncJournalFileRecord oldRecord; - if (!propagator()->_journal->getFileRecord(_item->_originalFile, &oldRecord)) { + if (!propagator()->_journal->getFileRecord(fileAlreadyMoved ? previousNameInDb : _item->_originalFile, &oldRecord)) { qCWarning(lcPropagateLocalRename) << "could not get file from local DB" << _item->_originalFile; done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(_item->_originalFile)); return; } - if (!propagator()->_journal->deleteFileRecord(_item->_originalFile)) { - qCWarning(lcPropagateLocalRename) << "could not delete file from local DB" << _item->_originalFile; - done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(_item->_originalFile)); - return; + + const auto deleteOldRecord = [this] (const QString &fileName) -> bool + { + SyncJournalFileRecord oldRecord; + if (!propagator()->_journal->getFileRecord(fileName, &oldRecord)) { + qCWarning(lcPropagateLocalRename) << "could not get file from local DB" << fileName; + done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(fileName)); + return false; + } + if (!propagator()->_journal->deleteFileRecord(fileName)) { + qCWarning(lcPropagateLocalRename) << "could not delete file from local DB" << fileName; + done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(fileName)); + return false; + } + + return true; + }; + + if (fileAlreadyMoved) { + if (!deleteOldRecord(previousNameInDb)) { + return; + } + } else { + if (!deleteOldRecord(_item->_originalFile)) { + return; + } } auto &vfs = propagator()->syncOptions()._vfs; @@ -282,6 +314,40 @@ void PropagateLocalRename::start() return; } } else { + auto dbQueryResult = propagator()->_journal->getFilesBelowPath(oldFile.toUtf8(), [oldFile, this] (const SyncJournalFileRecord &record) -> void { + const auto oldFileName = record._path; + const auto oldFileNameString = QString::fromUtf8(oldFileName); + auto newFileNameString = oldFileNameString; + newFileNameString.replace(0, oldFile.length(), _item->_renameTarget); + + if (oldFileNameString == newFileNameString) { + return; + } + + SyncJournalFileRecord oldRecord; + if (!propagator()->_journal->getFileRecord(oldFileName, &oldRecord)) { + qCWarning(lcPropagateLocalRename) << "could not get file from local DB" << oldFileName; + done(SyncFileItem::NormalError, tr("could not get file %1 from local DB").arg(oldFileNameString)); + return; + } + if (!propagator()->_journal->deleteFileRecord(oldFileName)) { + qCWarning(lcPropagateLocalRename) << "could not delete file from local DB" << oldFileName; + done(SyncFileItem::NormalError, tr("Could not delete file record %1 from local DB").arg(oldFileNameString)); + return; + } + + auto newItem = SyncFileItem::fromSyncJournalFileRecord(oldRecord); + newItem->_file = newFileNameString; + const auto result = propagator()->updateMetadata(*newItem); + if (!result) { + done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error())); + return; + } + }); + if (!dbQueryResult) { + done(SyncFileItem::FatalError, tr("Failed to propagate directory rename in hierarchy")); + return; + } propagator()->_renamedDirectories.insert(oldFile, _item->_renameTarget); if (!PropagateRemoteMove::adjustSelectiveSync(propagator()->_journal, oldFile, _item->_renameTarget)) { done(SyncFileItem::FatalError, tr("Failed to rename file")); diff --git a/src/libsync/propagatorjobs.h b/src/libsync/propagatorjobs.h index c1afb1959..3fa37ac03 100644 --- a/src/libsync/propagatorjobs.h +++ b/src/libsync/propagatorjobs.h @@ -86,10 +86,7 @@ class PropagateLocalRename : public PropagateItemJob { Q_OBJECT public: - PropagateLocalRename(OwncloudPropagator *propagator, const SyncFileItemPtr &item) - : PropagateItemJob(propagator, item) - { - } + PropagateLocalRename(OwncloudPropagator *propagator, const SyncFileItemPtr &item); void start() override; JobParallelism parallelism() override { return _item->isDirectory() ? WaitForFinished : FullParallelism; } };