Explorar o código

Conflict handling: add the OC-ConflictBasePath header

Issue #6702
Olivier Goffart %!s(int64=7) %!d(string=hai) anos
pai
achega
c3f745fa76

+ 14 - 3
src/common/syncjournaldb.cpp

@@ -741,6 +741,15 @@ bool SyncJournalDb::updateMetadataTableStructure()
         commitInternal("update database structure: add contentChecksum col for uploadinfo");
     }
 
+    if (!tableColumns("conflicts").contains("basePath")) {
+        SqlQuery query(_db);
+        query.prepare("ALTER TABLE conflicts ADD COLUMN basePath TEXT;");
+        if (!query.exec()) {
+            sqlFail("updateMetadataTableStructure: add basePath column", query);
+            re = false;
+        }
+    }
+
     if (true) {
         SqlQuery query(_db);
         query.prepare("CREATE INDEX IF NOT EXISTS metadata_e2e_id ON metadata(e2eMangledName);");
@@ -1978,13 +1987,14 @@ void SyncJournalDb::setConflictRecord(const ConflictRecord &record)
     auto &query = _setConflictRecordQuery;
     ASSERT(query.initOrReset(QByteArrayLiteral(
                           "INSERT OR REPLACE INTO conflicts "
-                          "(path, baseFileId, baseModtime, baseEtag) "
-                          "VALUES (?1, ?2, ?3, ?4);"),
+                          "(path, baseFileId, baseModtime, baseEtag, basePath) "
+                          "VALUES (?1, ?2, ?3, ?4, ?5);"),
         _db));
     query.bindValue(1, record.path);
     query.bindValue(2, record.baseFileId);
     query.bindValue(3, record.baseModtime);
     query.bindValue(4, record.baseEtag);
+    query.bindValue(5, record.basePath);
     ASSERT(query.exec());
 }
 
@@ -1996,7 +2006,7 @@ ConflictRecord SyncJournalDb::conflictRecord(const QByteArray &path)
     if (!checkConnect())
         return entry;
     auto &query = _getConflictRecordQuery;
-    ASSERT(query.initOrReset(QByteArrayLiteral("SELECT baseFileId, baseModtime, baseEtag FROM conflicts WHERE path=?1;"), _db));
+    ASSERT(query.initOrReset(QByteArrayLiteral("SELECT baseFileId, baseModtime, baseEtag, basePath FROM conflicts WHERE path=?1;"), _db));
     query.bindValue(1, path);
     ASSERT(query.exec());
     if (!query.next())
@@ -2006,6 +2016,7 @@ ConflictRecord SyncJournalDb::conflictRecord(const QByteArray &path)
     entry.baseFileId = query.baValue(0);
     entry.baseModtime = query.int64Value(1);
     entry.baseEtag = query.baValue(2);
+    entry.basePath = query.baValue(3);
     return entry;
 }
 

+ 8 - 0
src/common/syncjournalfilerecord.h

@@ -139,6 +139,14 @@ public:
      */
     QByteArray baseEtag;
 
+    /**
+     * The path of the original file
+     *
+     * maybe be empty if not available
+     */
+    QByteArray basePath;
+
+
     bool isValid() const { return !path.isEmpty(); }
 };
 }

+ 1 - 0
src/libsync/owncloudpropagator.cpp

@@ -691,6 +691,7 @@ bool OwncloudPropagator::createConflict(const SyncFileItemPtr &item,
     ConflictRecord conflictRecord;
     conflictRecord.path = conflictFileName.toUtf8();
     conflictRecord.baseModtime = item->_previousModtime;
+    conflictRecord.basePath = item->_file.toUtf8();
 
     SyncJournalFileRecord baseRecord;
     if (_journal->getFileRecord(item->_originalFile, &baseRecord) && baseRecord.isValid()) {

+ 3 - 2
src/libsync/propagatedownload.cpp

@@ -714,10 +714,11 @@ void PropagateDownloadFile::slotGetFinished()
     // the database yet!)
     if (job->reply()->rawHeader("OC-Conflict") == "1") {
         _conflictRecord.path = _item->_file.toUtf8();
+        _conflictRecord.basePath = job->reply()->rawHeader("OC-ConflictBasePath");
         _conflictRecord.baseFileId = job->reply()->rawHeader("OC-ConflictBaseFileId");
-        _conflictRecord.baseEtag = _job->reply()->rawHeader("OC-ConflictBaseEtag");
+        _conflictRecord.baseEtag = job->reply()->rawHeader("OC-ConflictBaseEtag");
 
-        auto mtimeHeader = _job->reply()->rawHeader("OC-ConflictBaseMtime");
+        auto mtimeHeader = job->reply()->rawHeader("OC-ConflictBaseMtime");
         if (!mtimeHeader.isEmpty())
             _conflictRecord.baseModtime = mtimeHeader.toLongLong();
 

+ 2 - 0
src/libsync/propagateupload.cpp

@@ -731,6 +731,8 @@ QMap<QByteArray, QByteArray> PropagateUploadFileCommon::headers()
     auto conflictRecord = propagator()->_journal->conflictRecord(_item->_file.toUtf8());
     if (conflictRecord.isValid()) {
         headers["OC-Conflict"] = "1";
+        if (!conflictRecord.basePath.isEmpty())
+            headers["OC-ConflictBasePath"] = conflictRecord.basePath;
         if (!conflictRecord.baseFileId.isEmpty())
             headers["OC-ConflictBaseFileId"] = conflictRecord.baseFileId;
         if (conflictRecord.baseModtime != -1)

+ 2 - 1
src/libsync/syncengine.cpp

@@ -278,9 +278,10 @@ void SyncEngine::conflictRecordMaintenance()
         if (!conflictRecordPaths.contains(bapath)) {
             ConflictRecord record;
             record.path = bapath;
+            auto basePath = Utility::conflictFileBaseNameFromPattern(bapath);
+            record.basePath = basePath;
 
             // Determine fileid of target file
-            auto basePath = Utility::conflictFileBaseNameFromPattern(bapath);
             SyncJournalFileRecord baseRecord;
             if (_journal->getFileRecord(basePath, &baseRecord) && baseRecord.isValid()) {
                 record.baseFileId = baseRecord._fileId;

+ 16 - 4
test/testsyncconflict.cpp

@@ -100,11 +100,15 @@ private slots:
         QMap<QByteArray, QString> conflictMap;
         fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *) -> QNetworkReply * {
             if (op == QNetworkAccessManager::PutOperation) {
-                auto baseFileId = request.rawHeader("OC-ConflictBaseFileId");
-                if (!baseFileId.isEmpty()) {
+                if (request.rawHeader("OC-Conflict") == "1") {
+                    auto baseFileId = request.rawHeader("OC-ConflictBaseFileId");
                     auto components = request.url().toString().split('/');
                     QString conflictFile = components.mid(components.size() - 2).join('/');
                     conflictMap[baseFileId] = conflictFile;
+                    [&] {
+                        QVERIFY(!baseFileId.isEmpty());
+                        QCOMPARE(request.rawHeader("OC-ConflictBasePath"), Utility::conflictFileBaseNameFromPattern(conflictFile.toUtf8()));
+                    }();
                 }
             }
             return nullptr;
@@ -146,11 +150,15 @@ private slots:
         QMap<QByteArray, QString> conflictMap;
         fakeFolder.setServerOverride([&](QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *) -> QNetworkReply * {
             if (op == QNetworkAccessManager::PutOperation) {
-                auto baseFileId = request.rawHeader("OC-ConflictBaseFileId");
-                if (!baseFileId.isEmpty()) {
+                if (request.rawHeader("OC-Conflict") == "1") {
+                    auto baseFileId = request.rawHeader("OC-ConflictBaseFileId");
                     auto components = request.url().toString().split('/');
                     QString conflictFile = components.mid(components.size() - 2).join('/');
                     conflictMap[baseFileId] = conflictFile;
+                    [&] {
+                        QVERIFY(!baseFileId.isEmpty());
+                        QCOMPARE(request.rawHeader("OC-ConflictBasePath"), Utility::conflictFileBaseNameFromPattern(conflictFile.toUtf8()));
+                    }();
                 }
             }
             return nullptr;
@@ -165,6 +173,7 @@ private slots:
         ConflictRecord conflictRecord;
         conflictRecord.path = conflictName.toUtf8();
         conflictRecord.baseFileId = a1FileId;
+        conflictRecord.basePath = "A/a1";
         fakeFolder.syncJournal().setConflictRecord(conflictRecord);
         QVERIFY(fakeFolder.syncOnce());
         QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
@@ -216,6 +225,7 @@ private slots:
         auto conflictRecord = fakeFolder.syncJournal().conflictRecord("A/a1 (conflicted copy 1234)");
         QVERIFY(conflictRecord.isValid());
         QCOMPARE(conflictRecord.baseFileId, fakeFolder.remoteModifier().find("A/a1")->fileId);
+        QCOMPARE(conflictRecord.basePath, "A/a1");
 
         // Now with server headers
         QObject parent;
@@ -227,6 +237,7 @@ private slots:
                 reply->setRawHeader("OC-ConflictBaseFileId", a2FileId);
                 reply->setRawHeader("OC-ConflictBaseMtime", "1234");
                 reply->setRawHeader("OC-ConflictBaseEtag", "etag");
+                reply->setRawHeader("OC-ConflictBasePath", "A/original");
                 return reply;
             }
             return nullptr;
@@ -239,6 +250,7 @@ private slots:
         QCOMPARE(conflictRecord.baseFileId, a2FileId);
         QCOMPARE(conflictRecord.baseModtime, 1234);
         QCOMPARE(conflictRecord.baseEtag, QByteArray("etag"));
+        QCOMPARE(conflictRecord.basePath, QByteArray("A/original"));
     }
 
     // Check that conflict records are removed when the file is gone