diff options
-rw-r--r-- | src/libsync/discovery.cpp | 74 | ||||
-rw-r--r-- | src/libsync/discoveryphase.h | 1 | ||||
-rw-r--r-- | src/libsync/propagateremotemove.cpp | 11 | ||||
-rw-r--r-- | src/libsync/propagateupload.cpp | 20 | ||||
-rw-r--r-- | test/testlocaldiscovery.cpp | 72 | ||||
-rw-r--r-- | test/testsyncvirtualfiles.cpp | 117 |
6 files changed, 261 insertions, 34 deletions
diff --git a/src/libsync/discovery.cpp b/src/libsync/discovery.cpp index 01cd608cd..ded16cc98 100644 --- a/src/libsync/discovery.cpp +++ b/src/libsync/discovery.cpp @@ -41,7 +41,7 @@ Q_LOGGING_CATEGORY(lcDisco, "sync.discovery", QtInfoMsg) bool ProcessDirectoryJob::checkForInvalidFileName(const PathTuple &path, const std::map<QString, Entries> &entries, Entries &entry) { - const auto originalFileName = entry.localEntry.name; + const auto originalFileName = entry.localEntry.isValid() ? entry.localEntry.name : entry.serverEntry.name; const auto newFileName = originalFileName.trimmed(); if (originalFileName == newFileName) { @@ -61,7 +61,7 @@ bool ProcessDirectoryJob::checkForInvalidFileName(const PathTuple &path, if (!errorMessage.isEmpty()) { auto item = SyncFileItemPtr::create(); - if (entry.localEntry.isDirectory) { + if ((entry.localEntry.isValid() && entry.localEntry.isDirectory) || (entry.serverEntry.isValid() && entry.serverEntry.isDirectory)) { item->_type = CSyncEnums::ItemTypeDirectory; } else { item->_type = CSyncEnums::ItemTypeFile; @@ -76,7 +76,11 @@ bool ProcessDirectoryJob::checkForInvalidFileName(const PathTuple &path, } } - entry.localEntry.renameName = newFileName; + if (entry.localEntry.isValid()) { + entry.localEntry.renameName = newFileName; + } else { + entry.serverEntry.renameName = newFileName; + } return true; } @@ -389,13 +393,6 @@ void ProcessDirectoryJob::processFile(PathTuple path, item->_originalFile = path._original; item->_previousSize = dbEntry._fileSize; item->_previousModtime = dbEntry._modtime; - if (!localEntry.renameName.isEmpty()) { - if (_dirItem) { - item->_renameTarget = _dirItem->_file + "/" + localEntry.renameName; - } else { - item->_renameTarget = localEntry.renameName; - } - } if (dbEntry._modtime == localEntry.modtime && dbEntry._type == ItemTypeVirtualFile && localEntry.type == ItemTypeFile) { item->_type = ItemTypeFile; @@ -602,6 +599,22 @@ void ProcessDirectoryJob::processFileAnalyzeRemoteInfo( // Unknown in db: new file on the server Q_ASSERT(!dbEntry.isValid()); + if (!serverEntry.renameName.isEmpty()) { + item->_renameTarget = _dirItem ? _dirItem->_file + "/" + serverEntry.renameName : serverEntry.renameName; + item->_originalFile = path._original; + item->_modtime = serverEntry.modtime; + item->_size = serverEntry.size; + item->_instruction = CSYNC_INSTRUCTION_RENAME; + item->_direction = SyncFileItem::Up; + item->_fileId = serverEntry.fileId; + item->_remotePerm = serverEntry.remotePerm; + item->_etag = serverEntry.etag; + item->_type = serverEntry.isDirectory ? CSyncEnums::ItemTypeDirectory : CSyncEnums::ItemTypeFile; + + processFileAnalyzeLocalInfo(item, path, localEntry, serverEntry, dbEntry, _queryServer); + return; + } + item->_instruction = CSYNC_INSTRUCTION_NEW; item->_direction = SyncFileItem::Down; item->_modtime = serverEntry.modtime; @@ -1005,6 +1018,42 @@ void ProcessDirectoryJob::processFileAnalyzeLocalInfo( return; } + if (!localEntry.renameName.isEmpty()) { + if (_dirItem) { + path._target = _dirItem->_file + "/" + localEntry.renameName; + } else { + path._target = localEntry.renameName; + } + OCC::SyncJournalFileRecord base; + if (!_discoveryData->_statedb->getFileRecordByInode(localEntry.inode, &base)) { + dbError(); + return; + } + const auto originalPath = base.path(); + const auto adjustedOriginalPath = _discoveryData->adjustRenamedPath(originalPath, SyncFileItem::Down); + _discoveryData->_renamedItemsLocal.insert(originalPath, path._target); + item->_renameTarget = path._target; + path._server = adjustedOriginalPath; + if (_dirItem) { + item->_file = _dirItem->_file + "/" + localEntry.name; + } else { + item->_file = localEntry.name; + } + path._original = originalPath; + item->_originalFile = path._original; + item->_modtime = base._modtime; + item->_inode = base._inode; + item->_instruction = CSYNC_INSTRUCTION_RENAME; + item->_direction = SyncFileItem::Down; + item->_fileId = base._fileId; + item->_remotePerm = base._remotePerm; + item->_etag = base._etag; + item->_type = base._type; + + finalize(); + return; + } + // New local file or rename item->_instruction = CSYNC_INSTRUCTION_NEW; item->_direction = SyncFileItem::Up; @@ -1341,10 +1390,11 @@ void ProcessDirectoryJob::processFileFinalize( if (isVfsWithSuffix()) { if (item->_type == ItemTypeVirtualFile) { addVirtualFileSuffix(path._target); - if (item->_instruction == CSYNC_INSTRUCTION_RENAME) + if (item->_instruction == CSYNC_INSTRUCTION_RENAME) { addVirtualFileSuffix(item->_renameTarget); - else + } else { addVirtualFileSuffix(item->_file); + } } if (item->_type == ItemTypeVirtualFileDehydration && item->_instruction == CSYNC_INSTRUCTION_SYNC) { diff --git a/src/libsync/discoveryphase.h b/src/libsync/discoveryphase.h index c894cfc2a..f5950e8dc 100644 --- a/src/libsync/discoveryphase.h +++ b/src/libsync/discoveryphase.h @@ -49,6 +49,7 @@ struct RemoteInfo { /** FileName of the entry (this does not contains any directory or path, just the plain name */ QString name; + QString renameName; QByteArray etag; QByteArray fileId; QByteArray checksumHeader; diff --git a/src/libsync/propagateremotemove.cpp b/src/libsync/propagateremotemove.cpp index edd29306c..5f5cdd06e 100644 --- a/src/libsync/propagateremotemove.cpp +++ b/src/libsync/propagateremotemove.cpp @@ -19,6 +19,7 @@ #include "common/syncjournalfilerecord.h" #include "filesystem.h" #include "common/asserts.h" +#include <QFileInfo> #include <QFile> #include <QStringList> #include <QDir> @@ -79,7 +80,7 @@ void PropagateRemoteMove::start() return; QString origin = propagator()->adjustRenamedPath(_item->_file); - qCDebug(lcPropagateRemoteMove) << origin << _item->_renameTarget; + qCInfo(lcPropagateRemoteMove) << origin << _item->_renameTarget; QString targetFile(propagator()->fullLocalPath(_item->_renameTarget)); @@ -254,6 +255,14 @@ void PropagateRemoteMove::finalize() newItem._size = oldRecord._fileSize; } } + + const auto targetFile = propagator()->fullLocalPath(_item->_renameTarget); + if (!QFileInfo::exists(targetFile)) { + propagator()->_journal->commit("Remote Rename"); + done(SyncFileItem::Success); + return; + } + const auto result = propagator()->updateMetadata(newItem); if (!result) { done(SyncFileItem::FatalError, tr("Error updating metadata: %1").arg(result.error())); diff --git a/src/libsync/propagateupload.cpp b/src/libsync/propagateupload.cpp index cf4e4fc7c..7a6a124ed 100644 --- a/src/libsync/propagateupload.cpp +++ b/src/libsync/propagateupload.cpp @@ -198,26 +198,6 @@ void PropagateUploadFileCommon::start() const auto slashPosition = path.lastIndexOf('/'); const auto parentPath = slashPosition >= 0 ? path.left(slashPosition) : QString(); - - if (!_item->_renameTarget.isEmpty() && _item->_file != _item->_renameTarget) { - // Try to rename the file - const auto originalFilePathAbsolute = propagator()->fullLocalPath(_item->_file); - const auto newFilePathAbsolute = propagator()->fullLocalPath(_item->_renameTarget); - const auto renameSuccess = QFile::rename(originalFilePathAbsolute, newFilePathAbsolute); - if (!renameSuccess) { - done(SyncFileItem::NormalError, "File contains trailing spaces and couldn't be renamed"); - return; - } - _item->_file = _item->_renameTarget; - _item->_modtime = FileSystem::getModTime(newFilePathAbsolute); - Q_ASSERT(_item->_modtime > 0); - if (_item->_modtime <= 0) { - qCWarning(lcPropagateUpload()) << "invalid modified time" << _item->_file << _item->_modtime; - slotOnErrorStartFolderUnlock(SyncFileItem::NormalError, tr("File %1 has invalid modified time. Do not upload to the server.").arg(QDir::toNativeSeparators(_item->_file))); - return; - } - } - SyncJournalFileRecord parentRec; bool ok = propagator()->_journal->getFileRecord(parentPath, &parentRec); if (!ok) { diff --git a/test/testlocaldiscovery.cpp b/test/testlocaldiscovery.cpp index 15e4898df..90499bfc9 100644 --- a/test/testlocaldiscovery.cpp +++ b/test/testlocaldiscovery.cpp @@ -207,7 +207,7 @@ private slots: void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedDoNotExist_renameAndUploadFile() { - FakeFolder fakeFolder { FileInfo::A12_B12_C12_S12() }; + FakeFolder fakeFolder{FileInfo{}}; QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); const QString fileWithSpaces1(" foo"); const QString fileWithSpaces2(" bar "); @@ -219,12 +219,33 @@ private slots: fakeFolder.localModifier().insert(fileWithSpaces1); fakeFolder.localModifier().insert(fileWithSpaces2); fakeFolder.localModifier().insert(fileWithSpaces3); + fakeFolder.localModifier().mkdir("A"); fakeFolder.localModifier().insert(fileWithSpaces4); fakeFolder.localModifier().insert(fileWithSpaces5); fakeFolder.localModifier().insert(fileWithSpaces6); QVERIFY(fakeFolder.syncOnce()); + QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces1.trimmed())); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces1)); + + QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces2.trimmed())); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces2)); + + QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces3.trimmed())); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces3)); + + QVERIFY(fakeFolder.currentLocalState().find("A/foo")); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4)); + + QVERIFY(fakeFolder.currentLocalState().find("A/bar")); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5)); + + QVERIFY(fakeFolder.currentLocalState().find("A/bla")); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6)); + + QVERIFY(fakeFolder.syncOnce()); + QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces1.trimmed())); QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces1)); QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces1.trimmed())); @@ -256,6 +277,55 @@ private slots: QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6)); } + void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedDoNotExist_renameFile() + { + FakeFolder fakeFolder{FileInfo{}}; + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + const QString fileWithSpaces4("A/ foo"); + const QString fileWithSpaces5("A/ bar "); + const QString fileWithSpaces6("A/bla "); + + fakeFolder.remoteModifier().mkdir("A"); + fakeFolder.remoteModifier().insert(fileWithSpaces4); + fakeFolder.remoteModifier().insert(fileWithSpaces5); + fakeFolder.remoteModifier().insert(fileWithSpaces6); + + qDebug() << fakeFolder.currentRemoteState(); + + QVERIFY(fakeFolder.syncOnce()); + + qDebug() << fakeFolder.currentRemoteState(); + + QVERIFY(fakeFolder.currentRemoteState().find("A/foo")); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4)); + + QVERIFY(fakeFolder.currentRemoteState().find("A/bar")); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5)); + + QVERIFY(fakeFolder.currentRemoteState().find("A/bla")); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6)); + + QVERIFY(fakeFolder.syncOnce()); + + QVERIFY(fakeFolder.currentRemoteState().find("A/foo")); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4)); + QVERIFY(fakeFolder.currentLocalState().find("A/foo")); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4)); + + QVERIFY(fakeFolder.currentRemoteState().find("A/bar")); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5)); + QVERIFY(fakeFolder.currentLocalState().find("A/bar")); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5)); + + QVERIFY(fakeFolder.currentRemoteState().find("A/bla")); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6)); + QVERIFY(fakeFolder.currentLocalState().find("A/bla")); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6)); + + auto expectedState = fakeFolder.currentLocalState(); + QCOMPARE(fakeFolder.currentRemoteState(), expectedState); + } + void testCreateFileWithTrailingSpaces_localTrimmedDoesExist_dontRenameAndUploadFile() { FakeFolder fakeFolder { FileInfo::A12_B12_C12_S12() }; diff --git a/test/testsyncvirtualfiles.cpp b/test/testsyncvirtualfiles.cpp index 5505c1f26..882879c7b 100644 --- a/test/testsyncvirtualfiles.cpp +++ b/test/testsyncvirtualfiles.cpp @@ -763,6 +763,123 @@ private slots: QVERIFY(dbRecord(fakeFolder, "case6-rename")._type == ItemTypeFile); } + void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedDoNotExist_renameAndUploadFile() + { + FakeFolder fakeFolder{ FileInfo() }; + setupVfs(fakeFolder); + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + + const QString fileWithSpaces1(" foo"); + const QString fileWithSpaces2(" bar "); + const QString fileWithSpaces3("bla "); + const QString fileWithSpaces4("A/ foo"); + const QString fileWithSpaces5("A/ bar "); + const QString fileWithSpaces6("A/bla "); + + fakeFolder.localModifier().insert(fileWithSpaces1); + fakeFolder.localModifier().insert(fileWithSpaces2); + fakeFolder.localModifier().insert(fileWithSpaces3); + fakeFolder.localModifier().mkdir("A"); + fakeFolder.localModifier().insert(fileWithSpaces4); + fakeFolder.localModifier().insert(fileWithSpaces5); + fakeFolder.localModifier().insert(fileWithSpaces6); + + QVERIFY(fakeFolder.syncOnce()); + + QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces1.trimmed())); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces1)); + + QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces2.trimmed())); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces2)); + + QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces3.trimmed())); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces3)); + + QVERIFY(fakeFolder.currentLocalState().find("A/foo")); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4)); + + QVERIFY(fakeFolder.currentLocalState().find("A/bar")); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5)); + + QVERIFY(fakeFolder.currentLocalState().find("A/bla")); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6)); + + QVERIFY(fakeFolder.syncOnce()); + + QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces1.trimmed())); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces1)); + QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces1.trimmed())); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces1)); + + QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces2.trimmed())); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces2)); + QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces2.trimmed())); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces2)); + + QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces3.trimmed())); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces3)); + QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces3.trimmed())); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces3)); + + QVERIFY(fakeFolder.currentRemoteState().find("A/foo")); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4)); + QVERIFY(fakeFolder.currentLocalState().find("A/foo")); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4)); + + QVERIFY(fakeFolder.currentRemoteState().find("A/bar")); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5)); + QVERIFY(fakeFolder.currentLocalState().find("A/bar")); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5)); + + QVERIFY(fakeFolder.currentRemoteState().find("A/bla")); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6)); + QVERIFY(fakeFolder.currentLocalState().find("A/bla")); + QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6)); + } + + void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedDoNotExist_renameFile() + { + FakeFolder fakeFolder{ FileInfo() }; + setupVfs(fakeFolder); + QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState()); + const QString fileWithSpaces4("A/ foo"); + const QString fileWithSpaces5("A/ bar "); + const QString fileWithSpaces6("A/bla "); + + fakeFolder.remoteModifier().mkdir("A"); + fakeFolder.remoteModifier().insert(fileWithSpaces4); + fakeFolder.remoteModifier().insert(fileWithSpaces5); + fakeFolder.remoteModifier().insert(fileWithSpaces6); + + QVERIFY(fakeFolder.syncOnce()); + + QVERIFY(fakeFolder.currentRemoteState().find("A/foo")); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4)); + + QVERIFY(fakeFolder.currentRemoteState().find("A/bar")); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5)); + + QVERIFY(fakeFolder.currentRemoteState().find("A/bla")); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6)); + + QVERIFY(fakeFolder.syncOnce()); + + QVERIFY(fakeFolder.currentRemoteState().find("A/foo")); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4)); + QVERIFY(fakeFolder.currentLocalState().find("A/foo" DVSUFFIX)); + QVERIFY(!fakeFolder.currentLocalState().find(QString{fileWithSpaces4 + DVSUFFIX})); + + QVERIFY(fakeFolder.currentRemoteState().find("A/bar")); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5)); + QVERIFY(fakeFolder.currentLocalState().find("A/bar" DVSUFFIX)); + QVERIFY(!fakeFolder.currentLocalState().find(QString{fileWithSpaces5 + DVSUFFIX})); + + QVERIFY(fakeFolder.currentRemoteState().find("A/bla")); + QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6)); + QVERIFY(fakeFolder.currentLocalState().find("A/bla" DVSUFFIX)); + QVERIFY(!fakeFolder.currentLocalState().find(QString{fileWithSpaces6 + DVSUFFIX})); + } + // Dehydration via sync works void testSyncDehydration() { |