Bugfix. Folder case clash conflict. Do not update parent folder record if it contains...
authoralex-z <blackslayer4@gmail.com>
Thu, 18 Apr 2024 21:49:47 +0000 (23:49 +0200)
committerbackportbot[bot] <backportbot[bot]@users.noreply.github.com>
Tue, 23 Apr 2024 10:18:39 +0000 (10:18 +0000)
Signed-off-by: alex-z <blackslayer4@gmail.com>
src/libsync/owncloudpropagator.cpp
src/libsync/owncloudpropagator.h
src/libsync/propagatorjobs.cpp
src/libsync/syncfileitem.h

index a4d21a2e3b85c646722fa686af76e431438e6d48..7016c8d18521f508b50f43788ee3f85adf0d907a 100644 (file)
@@ -1291,6 +1291,11 @@ void PropagatorCompositeJob::slotSubJobFinished(SyncFileItem::Status status)
     auto *subJob = dynamic_cast<PropagatorJob *>(sender());
     ASSERT(subJob);
 
+    if (!_isAnyCaseClashSubFolder) {
+        if (const auto propagateDirectoryjob = qobject_cast<PropagateDirectory *>(subJob)) {
+            _isAnyCaseClashSubFolder = propagateDirectoryjob->_item && propagateDirectoryjob->_item->_isCaseClashFolder;
+        }
+    }
     // Delete the job and remove it from our list of jobs.
     subJob->deleteLater();
     int i = _runningJobs.indexOf(subJob);
@@ -1496,15 +1501,16 @@ void PropagateDirectory::slotSubJobsFinished(SyncFileItem::Status status)
                 }
             }
 #endif
-
-            const auto result = propagator()->updateMetadata(*_item);
-            if (!result) {
-                status = _item->_status = SyncFileItem::FatalError;
-                _item->_errorString = tr("Error updating metadata: %1").arg(result.error());
-                qCWarning(lcDirectory) << "Error writing to the database for file" << _item->_file << "with" << result.error();
-            } else if (*result == Vfs::ConvertToPlaceholderResult::Locked) {
-                _item->_status = SyncFileItem::SoftError;
-                _item->_errorString = tr("File is currently in use");
+            if (!_subJobs._isAnyCaseClashSubFolder) {
+                const auto result = propagator()->updateMetadata(*_item);
+                if (!result) {
+                    status = _item->_status = SyncFileItem::FatalError;
+                    _item->_errorString = tr("Error updating metadata: %1").arg(result.error());
+                    qCWarning(lcDirectory) << "Error writing to the database for file" << _item->_file << "with" << result.error();
+                } else if (*result == Vfs::ConvertToPlaceholderResult::Locked) {
+                    _item->_status = SyncFileItem::SoftError;
+                    _item->_errorString = tr("File is currently in use");
+                }
             }
         }
     }
index 0e4640e22cf8f6e4cd388c4285da3a49c16b286d..5c5efa5cfbc4a8e379d8d4152cdbe2cae1e82b23 100644 (file)
@@ -246,6 +246,7 @@ public:
     QVector<PropagatorJob *> _runningJobs;
     SyncFileItem::Status _hasError = SyncFileItem::NoStatus; // NoStatus,  or NormalError / SoftError if there was an error
     quint64 _abortsCount = 0;
+    bool _isAnyCaseClashSubFolder = false;
 
     explicit PropagatorCompositeJob(OwncloudPropagator *propagator)
         : PropagatorJob(propagator)
index 21390cb08461e5da12b078413fdbf727fdc1c8c2..4c40b68278a506a81410515eb62a12b2dad00d90 100644 (file)
@@ -183,6 +183,7 @@ void PropagateLocalMkdir::startLocalMkdir()
     }
 
     if (Utility::fsCasePreserving() && propagator()->localFileNameClash(_item->_file)) {
+        _item->_isCaseClashFolder = true;
         qCWarning(lcPropagateLocalMkdir) << "New folder to create locally already exists with different case:" << _item->_file;
         done(SyncFileItem::FileNameClash, tr("Folder %1 cannot be created because of a local file or folder name clash!").arg(newDirStr), ErrorCategory::GenericError);
         return;
@@ -302,7 +303,17 @@ void PropagateLocalRename::start()
         if (QString::compare(_item->_file, _item->_renameTarget, Qt::CaseInsensitive) != 0
             && propagator()->localFileNameClash(_item->_renameTarget)) {
 
-            qCInfo(lcPropagateLocalRename) << "renaming a case clashed file" << _item->_file << _item->_renameTarget;
+            qCInfo(lcPropagateLocalRename) << "renaming a case clashed item" << _item->_file << _item->_renameTarget;
+            if (_item->isDirectory()) {
+                // #HotFix
+                // fix a crash (we can not create a conflicted copy for folders)
+                // right now, the conflict resolution will not even work for this scenario with folders,
+                // but, let's fix it step by step, this will be a second stage
+                done(SyncFileItem::FileNameClash,
+                     tr("Folder %1 cannot be renamed because of a local file or folder name clash!").arg(_item->_file),
+                     ErrorCategory::GenericError);
+                return;
+            }
             const auto caseClashConflictResult = propagator()->createCaseClashConflict(_item, existingFile);
             if (caseClashConflictResult) {
                 done(SyncFileItem::SoftError, *caseClashConflictResult, ErrorCategory::GenericError);
index d06e6f6d93b23ca4c6991428af234a749f2b171b..de01c1c4d9b4459876bdf3ee471d347d5271e5d5 100644 (file)
@@ -335,6 +335,8 @@ public:
     bool _isFileDropDetected = false;
 
     bool _isEncryptedMetadataNeedUpdate = false;
+
+    bool _isCaseClashFolder = false;
 };
 
 inline bool operator<(const SyncFileItemPtr &item1, const SyncFileItemPtr &item2)