Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/desktop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorallexzander <allexzander@users.noreply.github.com>2022-05-16 18:08:15 +0300
committerGitHub <noreply@github.com>2022-05-16 18:08:15 +0300
commitfc8bfdc9f30183ac056661d0e00a9b6e32caec3f (patch)
treef230fcfa27ba202651519b30c28026b7298ce6f5
parent96e4fceecf619407556171ad29738b5d27c39eae (diff)
parent53654b2a505ac2b6b56eac83b0a4696125f1c30e (diff)
Merge pull request #4454 from nextcloud/bugfix/allow-manual-rename-files-with-spaces
Bugfix/allow manual rename files with spaces
-rw-r--r--src/csync/csync_exclude.cpp4
-rw-r--r--src/csync/csync_exclude.h2
-rw-r--r--src/gui/folder.cpp5
-rw-r--r--src/gui/folder.h2
-rw-r--r--src/gui/invalidfilenamedialog.cpp131
-rw-r--r--src/gui/invalidfilenamedialog.h14
-rw-r--r--src/gui/tray/activitylistmodel.cpp4
-rw-r--r--src/libsync/discovery.cpp108
-rw-r--r--src/libsync/discovery.h5
-rw-r--r--src/libsync/discoveryphase.h1
-rw-r--r--src/libsync/syncengine.cpp7
-rw-r--r--src/libsync/syncengine.h4
-rw-r--r--src/libsync/syncresult.cpp2
-rw-r--r--test/testlocaldiscovery.cpp179
-rw-r--r--test/testsyncvirtualfiles.cpp162
15 files changed, 385 insertions, 245 deletions
diff --git a/src/csync/csync_exclude.cpp b/src/csync/csync_exclude.cpp
index eb8507589..e367f37dd 100644
--- a/src/csync/csync_exclude.cpp
+++ b/src/csync/csync_exclude.cpp
@@ -165,9 +165,7 @@ static CSYNC_EXCLUDE_TYPE _csync_excluded_common(const QString &path, bool exclu
// as '.' is a separator that is not stored internally, so let's
// not allow to sync those to avoid file loss/ambiguities (#416)
if (blen > 1) {
- if (bname.at(blen - 1) == QLatin1Char(' ')) {
- return CSYNC_FILE_EXCLUDE_TRAILING_SPACE;
- } else if (bname.at(blen - 1) == QLatin1Char('.')) {
+ if (bname.at(blen - 1) == QLatin1Char('.')) {
return CSYNC_FILE_EXCLUDE_INVALID_CHAR;
}
}
diff --git a/src/csync/csync_exclude.h b/src/csync/csync_exclude.h
index 856ac67ef..558dea30b 100644
--- a/src/csync/csync_exclude.h
+++ b/src/csync/csync_exclude.h
@@ -45,6 +45,8 @@ enum CSYNC_EXCLUDE_TYPE {
CSYNC_FILE_EXCLUDE_CONFLICT,
CSYNC_FILE_EXCLUDE_CANNOT_ENCODE,
CSYNC_FILE_EXCLUDE_SERVER_BLACKLISTED,
+ CSYNC_FILE_EXCLUDE_LEADING_SPACE,
+ CSYNC_FILE_EXCLUDE_LEADING_AND_TRAILING_SPACE,
};
class ExcludedFilesTest;
diff --git a/src/gui/folder.cpp b/src/gui/folder.cpp
index 6da7388db..0ad6e8bad 100644
--- a/src/gui/folder.cpp
+++ b/src/gui/folder.cpp
@@ -1225,6 +1225,11 @@ void Folder::scheduleThisFolderSoon()
}
}
+void Folder::acceptInvalidFileName(const QString &filePath)
+{
+ _engine->addAcceptedInvalidFileName(filePath);
+}
+
void Folder::setSaveBackwardsCompatible(bool save)
{
_saveBackwardsCompatible = save;
diff --git a/src/gui/folder.h b/src/gui/folder.h
index e18aecbfa..e38cc091c 100644
--- a/src/gui/folder.h
+++ b/src/gui/folder.h
@@ -256,6 +256,8 @@ public:
*/
void scheduleThisFolderSoon();
+ void acceptInvalidFileName(const QString &filePath);
+
/**
* Migration: When this flag is true, this folder will save to
* the backwards-compatible 'Folders' section in the config file.
diff --git a/src/gui/invalidfilenamedialog.cpp b/src/gui/invalidfilenamedialog.cpp
index 8b318fed3..d71783534 100644
--- a/src/gui/invalidfilenamedialog.cpp
+++ b/src/gui/invalidfilenamedialog.cpp
@@ -18,6 +18,7 @@
#include "propagateremotemove.h"
#include "ui_invalidfilenamedialog.h"
+#include "filesystem.h"
#include <folder.h>
#include <QPushButton>
@@ -84,13 +85,18 @@ InvalidFilenameDialog::InvalidFilenameDialog(AccountPtr account, Folder *folder,
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
_ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Rename file"));
- _ui->descriptionLabel->setText(tr("The file %1 could not be synced because the name contains characters which are not allowed on this system.").arg(_originalFileName));
- _ui->explanationLabel->setText(tr("The following characters are not allowed on the system: * \" | & ? , ; : \\ / ~ < >"));
+ _ui->descriptionLabel->setText(tr("The file \"%1\" could not be synced because the name contains characters which are not allowed on this system.").arg(_originalFileName));
+ _ui->explanationLabel->setText(tr("The following characters are not allowed on the system: * \" | & ? , ; : \\ / ~ < > leading/trailing spaces"));
_ui->filenameLineEdit->setText(filePathFileInfo.fileName());
connect(_ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(_ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
+ _ui->errorLabel->setText(
+ tr("Checking rename permissions..."));
+ _ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
+ _ui->filenameLineEdit->setEnabled(false);
+
connect(_ui->filenameLineEdit, &QLineEdit::textChanged, this,
&InvalidFilenameDialog::onFilenameLineEditTextChanged);
@@ -104,30 +110,88 @@ void InvalidFilenameDialog::checkIfAllowedToRename()
const auto propfindJob = new PropfindJob(_account, QDir::cleanPath(_folder->remotePath() + _originalFileName));
propfindJob->setProperties({ "http://owncloud.org/ns:permissions" });
connect(propfindJob, &PropfindJob::result, this, &InvalidFilenameDialog::onPropfindPermissionSuccess);
+ connect(propfindJob, &PropfindJob::finishedWithError, this, &InvalidFilenameDialog::onPropfindPermissionError);
propfindJob->start();
}
-void InvalidFilenameDialog::onPropfindPermissionSuccess(const QVariantMap &values)
+void InvalidFilenameDialog::onCheckIfAllowedToRenameComplete(const QVariantMap &values, QNetworkReply *reply)
{
- if (!values.contains("permissions")) {
- return;
- }
- const auto remotePermissions = RemotePermissions::fromServerString(values["permissions"].toString());
- if (!remotePermissions.hasPermission(remotePermissions.CanRename)
- || !remotePermissions.hasPermission(remotePermissions.CanMove)) {
+ const auto isAllowedToRename = [](const RemotePermissions remotePermissions) {
+ return remotePermissions.hasPermission(remotePermissions.CanRename)
+ && remotePermissions.hasPermission(remotePermissions.CanMove);
+ };
+
+ if (values.contains("permissions") && !isAllowedToRename(RemotePermissions::fromServerString(values["permissions"].toString()))) {
_ui->errorLabel->setText(
tr("You don't have the permission to rename this file. Please ask the author of the file to rename it."));
- _ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
- _ui->filenameLineEdit->setEnabled(false);
+ return;
+ } else if (reply) {
+ if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() != 404) {
+ _ui->errorLabel->setText(
+ tr("Failed to fetch permissions with error %1").arg(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()));
+ return;
+ }
}
+
+ _ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
+ _ui->filenameLineEdit->setEnabled(true);
+ _ui->filenameLineEdit->selectAll();
+
+ const auto filePathFileInfo = QFileInfo(_filePath);
+ const auto fileName = filePathFileInfo.fileName();
+ processLeadingOrTrailingSpacesError(fileName);
+}
+
+bool InvalidFilenameDialog::processLeadingOrTrailingSpacesError(const QString &fileName)
+{
+ const auto hasLeadingSpaces = fileName.startsWith(QLatin1Char(' '));
+ const auto hasTrailingSpaces = fileName.endsWith(QLatin1Char(' '));
+
+ _ui->buttonBox->setStandardButtons(_ui->buttonBox->standardButtons() &~ QDialogButtonBox::No);
+
+ if (hasLeadingSpaces || hasTrailingSpaces) {
+ if (hasLeadingSpaces && hasTrailingSpaces) {
+ _ui->errorLabel->setText(tr("Filename contains leading and trailing spaces."));
+ }
+ else if (hasLeadingSpaces) {
+ _ui->errorLabel->setText(tr("Filename contains leading spaces."));
+ } else if (hasTrailingSpaces) {
+ _ui->errorLabel->setText(tr("Filename contains trailing spaces."));
+ }
+
+ if (!Utility::isWindows()) {
+ _ui->buttonBox->setStandardButtons(_ui->buttonBox->standardButtons() | QDialogButtonBox::No);
+ _ui->buttonBox->button(QDialogButtonBox::No)->setText(tr("Use invalid name"));
+ connect(_ui->buttonBox->button(QDialogButtonBox::No), &QPushButton::clicked, this, &InvalidFilenameDialog::useInvalidName);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+void InvalidFilenameDialog::onPropfindPermissionSuccess(const QVariantMap &values)
+{
+ onCheckIfAllowedToRenameComplete(values);
+}
+
+void InvalidFilenameDialog::onPropfindPermissionError(QNetworkReply *reply)
+{
+ onCheckIfAllowedToRenameComplete({}, reply);
+}
+
+void InvalidFilenameDialog::useInvalidName()
+{
+ emit acceptedInvalidName(_filePath);
}
void InvalidFilenameDialog::accept()
{
_newFilename = _relativeFilePath + _ui->filenameLineEdit->text().trimmed();
const auto propfindJob = new PropfindJob(_account, QDir::cleanPath(_folder->remotePath() + _newFilename));
- connect(propfindJob, &PropfindJob::result, this, &InvalidFilenameDialog::onRemoteFileAlreadyExists);
- connect(propfindJob, &PropfindJob::finishedWithError, this, &InvalidFilenameDialog::onRemoteFileDoesNotExist);
+ connect(propfindJob, &PropfindJob::result, this, &InvalidFilenameDialog::onRemoteDestinationFileAlreadyExists);
+ connect(propfindJob, &PropfindJob::finishedWithError, this, &InvalidFilenameDialog::onRemoteDestinationFileDoesNotExist);
propfindJob->start();
}
@@ -138,11 +202,10 @@ void InvalidFilenameDialog::onFilenameLineEditTextChanged(const QString &text)
const auto containsIllegalChars = !illegalContainedCharacters.empty() || text.endsWith(QLatin1Char('.'));
const auto isTextValid = isNewFileNameDifferent && !containsIllegalChars;
- if (isTextValid) {
- _ui->errorLabel->setText("");
- } else {
- _ui->errorLabel->setText(tr("Filename contains illegal characters: %1")
- .arg(illegalCharacterListToString(illegalContainedCharacters)));
+ _ui->errorLabel->setText("");
+
+ if (!processLeadingOrTrailingSpacesError(text) && !isTextValid){
+ _ui->errorLabel->setText(tr("Filename contains illegal characters: %1").arg(illegalCharacterListToString(illegalContainedCharacters)));
}
_ui->buttonBox->button(QDialogButtonBox::Ok)
@@ -162,7 +225,7 @@ void InvalidFilenameDialog::onMoveJobFinished()
QDialog::accept();
}
-void InvalidFilenameDialog::onRemoteFileAlreadyExists(const QVariantMap &values)
+void InvalidFilenameDialog::onRemoteDestinationFileAlreadyExists(const QVariantMap &values)
{
Q_UNUSED(values);
@@ -170,15 +233,41 @@ void InvalidFilenameDialog::onRemoteFileAlreadyExists(const QVariantMap &values)
_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
}
-void InvalidFilenameDialog::onRemoteFileDoesNotExist(QNetworkReply *reply)
+void InvalidFilenameDialog::onRemoteDestinationFileDoesNotExist(QNetworkReply *reply)
{
Q_UNUSED(reply);
- // File does not exist. We can rename it.
+ const auto propfindJob = new PropfindJob(_account, QDir::cleanPath(_folder->remotePath() + _originalFileName));
+ connect(propfindJob, &PropfindJob::result, this, &InvalidFilenameDialog::onRemoteSourceFileAlreadyExists);
+ connect(propfindJob, &PropfindJob::finishedWithError, this, &InvalidFilenameDialog::onRemoteSourceFileDoesNotExist);
+ propfindJob->start();
+}
+
+void InvalidFilenameDialog::onRemoteSourceFileAlreadyExists(const QVariantMap &values)
+{
+ Q_UNUSED(values);
+
+ // Remote source file exists. We need to start MoveJob to rename it
const auto remoteSource = QDir::cleanPath(_folder->remotePath() + _originalFileName);
const auto remoteDestionation = QDir::cleanPath(_account->davUrl().path() + _folder->remotePath() + _newFilename);
const auto moveJob = new MoveJob(_account, remoteSource, remoteDestionation, this);
connect(moveJob, &MoveJob::finishedSignal, this, &InvalidFilenameDialog::onMoveJobFinished);
moveJob->start();
}
+
+void InvalidFilenameDialog::onRemoteSourceFileDoesNotExist(QNetworkReply *reply)
+{
+ Q_UNUSED(reply);
+
+ // It's a new file we've just created locally. We will attempt to rename it locally.
+ const auto localSource = QDir::cleanPath(_folder->path() + _originalFileName);
+ const auto localDestionation = QDir::cleanPath(_folder->path()+ _newFilename);
+
+ QString error;
+ if (!FileSystem::rename(localSource, localDestionation, &error)) {
+ _ui->errorLabel->setText(tr("Could not rename local file. %1").arg(error));
+ return;
+ }
+ QDialog::accept();
+}
}
diff --git a/src/gui/invalidfilenamedialog.h b/src/gui/invalidfilenamedialog.h
index 2b6ff0ded..f55b76de3 100644
--- a/src/gui/invalidfilenamedialog.h
+++ b/src/gui/invalidfilenamedialog.h
@@ -41,6 +41,9 @@ public:
void accept() override;
+signals:
+ void acceptedInvalidName(const QString &filePath);
+
private:
std::unique_ptr<Ui::InvalidFilenameDialog> _ui;
@@ -53,9 +56,16 @@ private:
void onFilenameLineEditTextChanged(const QString &text);
void onMoveJobFinished();
- void onRemoteFileAlreadyExists(const QVariantMap &values);
- void onRemoteFileDoesNotExist(QNetworkReply *reply);
+ void onRemoteDestinationFileAlreadyExists(const QVariantMap &values);
+ void onRemoteDestinationFileDoesNotExist(QNetworkReply *reply);
+ void onRemoteSourceFileAlreadyExists(const QVariantMap &values);
+ void onRemoteSourceFileDoesNotExist(QNetworkReply *reply);
void checkIfAllowedToRename();
+ void onCheckIfAllowedToRenameComplete(const QVariantMap &values, QNetworkReply *reply = nullptr);
+ bool processLeadingOrTrailingSpacesError(const QString &fileName);
void onPropfindPermissionSuccess(const QVariantMap &values);
+ void onPropfindPermissionError(QNetworkReply *reply = nullptr);
+private slots:
+ void useInvalidName();
};
}
diff --git a/src/gui/tray/activitylistmodel.cpp b/src/gui/tray/activitylistmodel.cpp
index 87fb8dcc9..ebf6b7512 100644
--- a/src/gui/tray/activitylistmodel.cpp
+++ b/src/gui/tray/activitylistmodel.cpp
@@ -688,6 +688,10 @@ void ActivityListModel::slotTriggerDefaultAction(const int activityIndex)
connect(_currentInvalidFilenameDialog, &InvalidFilenameDialog::accepted, folder, [folder]() {
folder->scheduleThisFolderSoon();
});
+ connect(_currentInvalidFilenameDialog, &InvalidFilenameDialog::acceptedInvalidName, folder, [folder](const QString& filePath) {
+ folder->acceptInvalidFileName(filePath);
+ folder->scheduleThisFolderSoon();
+ });
_currentInvalidFilenameDialog->open();
ownCloudGui::raiseDialog(_currentInvalidFilenameDialog);
return;
diff --git a/src/libsync/discovery.cpp b/src/libsync/discovery.cpp
index 7527d06d5..43cfaa100 100644
--- a/src/libsync/discovery.cpp
+++ b/src/libsync/discovery.cpp
@@ -37,54 +37,6 @@ namespace OCC {
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.isValid() ? entry.localEntry.name : entry.serverEntry.name;
- const auto newFileName = originalFileName.trimmed();
-
- if (originalFileName == newFileName) {
- return true;
- }
-
- const auto entriesIter = entries.find(newFileName);
- if (entriesIter != entries.end()) {
- QString errorMessage;
- const auto newFileNameEntry = entriesIter->second;
- if (entry.serverEntry.isValid() && newFileNameEntry.serverEntry.isValid()) {
- errorMessage = tr("File contains trailing spaces and could not be renamed, because a file with the same name already exists on the server.");
- }
- if (entry.localEntry.isValid() && newFileNameEntry.localEntry.isValid()) {
- errorMessage = tr("File contains trailing spaces and could not be renamed, because a file with the same name already exists locally.");
- }
-
- if (!errorMessage.isEmpty()) {
- auto item = SyncFileItemPtr::create();
- if ((entry.localEntry.isValid() && entry.localEntry.isDirectory) || (entry.serverEntry.isValid() && entry.serverEntry.isDirectory)) {
- item->_type = CSyncEnums::ItemTypeDirectory;
- } else {
- item->_type = CSyncEnums::ItemTypeFile;
- }
- item->_file = path._target;
- item->_originalFile = path._target;
- item->_instruction = CSYNC_INSTRUCTION_ERROR;
- item->_status = SyncFileItem::NormalError;
- item->_errorString = errorMessage;
- processFileFinalize(item, path, false, ParentNotChanged, ParentNotChanged);
- return false;
- }
- }
-
- if (entry.localEntry.isValid()) {
- entry.localEntry.renameName = newFileName;
- } else {
- entry.serverEntry.renameName = newFileName;
- }
-
- return true;
-}
-
void ProcessDirectoryJob::start()
{
qCInfo(lcDisco) << "STARTING" << _currentFolder._server << _queryServer << _currentFolder._local << _queryLocal;
@@ -222,33 +174,46 @@ void ProcessDirectoryJob::process()
// local stat function.
// Recall file shall not be ignored (#4420)
bool isHidden = e.localEntry.isHidden || (!f.first.isEmpty() && f.first[0] == '.' && f.first != QLatin1String(".sys.admin#recall#"));
-#ifdef Q_OS_WIN
- // exclude ".lnk" files as they are not essential, but, causing troubles when enabling the VFS due to QFileInfo::isDir() and other methods are freezing, which causes the ".lnk" files to start hydrating and freezing the app eventually.
- const bool isServerEntryWindowsShortcut = !e.localEntry.isValid() && e.serverEntry.isValid() && !e.serverEntry.isDirectory && FileSystem::isLnkFile(e.serverEntry.name);
-#else
- const bool isServerEntryWindowsShortcut = false;
-#endif
- if (handleExcluded(path._target, e.localEntry.name,
- e.localEntry.isDirectory || e.serverEntry.isDirectory, isHidden,
- e.localEntry.isSymLink || isServerEntryWindowsShortcut))
+ if (handleExcluded(path._target, e, isHidden))
continue;
if (_queryServer == InBlackList || _discoveryData->isInSelectiveSyncBlackList(path._original)) {
processBlacklisted(path, e.localEntry, e.dbEntry);
continue;
}
- if (!checkForInvalidFileName(path, entries, e)) {
- continue;
- }
processFile(std::move(path), e.localEntry, e.serverEntry, e.dbEntry);
}
QTimer::singleShot(0, _discoveryData, &DiscoveryPhase::scheduleMoreJobs);
}
-bool ProcessDirectoryJob::handleExcluded(const QString &path, const QString &localName, bool isDirectory, bool isHidden, bool isSymlink)
+bool ProcessDirectoryJob::handleExcluded(const QString &path, const Entries &entries, bool isHidden)
{
+ const auto isDirectory = entries.localEntry.isDirectory || entries.serverEntry.isDirectory;
+
auto excluded = _discoveryData->_excludes->traversalPatternMatch(path, isDirectory ? ItemTypeDirectory : ItemTypeFile);
+ const auto fileName = path.mid(path.lastIndexOf('/') + 1);
+
+ if (excluded == CSYNC_NOT_EXCLUDED) {
+ const auto endsWithSpace = fileName.endsWith(QLatin1Char(' '));
+ const auto startsWithSpace = fileName.startsWith(QLatin1Char(' '));
+ if (startsWithSpace && endsWithSpace) {
+ excluded = CSYNC_FILE_EXCLUDE_LEADING_AND_TRAILING_SPACE;
+ } else if (endsWithSpace) {
+ excluded = CSYNC_FILE_EXCLUDE_TRAILING_SPACE;
+ } else if (startsWithSpace) {
+ excluded = CSYNC_FILE_EXCLUDE_LEADING_SPACE;
+ }
+ }
+
+ // we don't need to trigger a warning if trailing/leading space file is already on the server or has already been synced down
+ // only if the OS supports trailing/leading spaces
+ const auto wasSyncedAlreadyAndOsSupportsSpaces = !Utility::isWindows() && (entries.serverEntry.isValid() || entries.dbEntry.isValid());
+ if ((excluded == CSYNC_FILE_EXCLUDE_LEADING_SPACE || excluded == CSYNC_FILE_EXCLUDE_TRAILING_SPACE || excluded == CSYNC_FILE_EXCLUDE_LEADING_AND_TRAILING_SPACE)
+ && (wasSyncedAlreadyAndOsSupportsSpaces || _discoveryData->_leadingAndTrailingSpacesFilesAllowed.contains(_discoveryData->_localDir + path))) {
+ excluded = CSYNC_NOT_EXCLUDED;
+ }
+
// FIXME: move to ExcludedFiles 's regexp ?
bool isInvalidPattern = false;
if (excluded == CSYNC_NOT_EXCLUDED && !_discoveryData->_invalidFilenameRx.pattern().isEmpty()) {
@@ -260,6 +225,8 @@ bool ProcessDirectoryJob::handleExcluded(const QString &path, const QString &loc
if (excluded == CSYNC_NOT_EXCLUDED && _discoveryData->_ignoreHiddenFiles && isHidden) {
excluded = CSYNC_FILE_EXCLUDE_HIDDEN;
}
+
+ const auto &localName = entries.localEntry.name;
if (excluded == CSYNC_NOT_EXCLUDED && !localName.isEmpty()
&& _discoveryData->_serverBlacklistedFiles.contains(localName)) {
excluded = CSYNC_FILE_EXCLUDE_SERVER_BLACKLISTED;
@@ -280,6 +247,17 @@ bool ProcessDirectoryJob::handleExcluded(const QString &path, const QString &loc
}
}
+#ifdef Q_OS_WIN
+ // exclude ".lnk" files as they are not essential, but, causing troubles when enabling the VFS due to
+ // QFileInfo::isDir() and other methods are freezing, which causes the ".lnk" files to start hydrating and freezing
+ // the app eventually.
+ const bool isServerEntryWindowsShortcut = !entries.localEntry.isValid() && entries.serverEntry.isValid()
+ && !entries.serverEntry.isDirectory && FileSystem::isLnkFile(entries.serverEntry.name);
+#else
+ const bool isServerEntryWindowsShortcut = false;
+#endif
+ const auto isSymlink = entries.localEntry.isSymLink || isServerEntryWindowsShortcut;
+
if (excluded == CSYNC_NOT_EXCLUDED && !isSymlink) {
return false;
} else if (excluded == CSYNC_FILE_SILENTLY_EXCLUDED || excluded == CSYNC_FILE_EXCLUDE_AND_REMOVE) {
@@ -329,6 +307,14 @@ bool ProcessDirectoryJob::handleExcluded(const QString &path, const QString &loc
item->_errorString = tr("Filename contains trailing spaces.");
item->_status = SyncFileItem::FileNameInvalid;
break;
+ case CSYNC_FILE_EXCLUDE_LEADING_SPACE:
+ item->_errorString = tr("Filename contains leading spaces.");
+ item->_status = SyncFileItem::FileNameInvalid;
+ break;
+ case CSYNC_FILE_EXCLUDE_LEADING_AND_TRAILING_SPACE:
+ item->_errorString = tr("Filename contains leading and trailing spaces.");
+ item->_status = SyncFileItem::FileNameInvalid;
+ break;
case CSYNC_FILE_EXCLUDE_LONG_FILENAME:
item->_errorString = tr("Filename is too long.");
item->_status = SyncFileItem::FileNameInvalid;
diff --git a/src/libsync/discovery.h b/src/libsync/discovery.h
index 97c11d9cf..3e18d81d2 100644
--- a/src/libsync/discovery.h
+++ b/src/libsync/discovery.h
@@ -150,8 +150,6 @@ private:
}
};
- bool checkForInvalidFileName(const PathTuple &path, const std::map<QString, Entries> &entries, Entries &entry);
-
/** Iterate over entries inside the directory (non-recursively).
*
* Called once _serverEntries and _localEntries are filled
@@ -162,8 +160,7 @@ private:
// return true if the file is excluded.
// path is the full relative path of the file. localName is the base name of the local entry.
- bool handleExcluded(const QString &path, const QString &localName, bool isDirectory,
- bool isHidden, bool isSymlink);
+ bool handleExcluded(const QString &path, const Entries &entries, bool isHidden);
/** Reconcile local/remote/db information for a single item.
*
diff --git a/src/libsync/discoveryphase.h b/src/libsync/discoveryphase.h
index 3f5240dd1..f4bb42704 100644
--- a/src/libsync/discoveryphase.h
+++ b/src/libsync/discoveryphase.h
@@ -271,6 +271,7 @@ public:
ExcludedFiles *_excludes;
QRegularExpression _invalidFilenameRx; // FIXME: maybe move in ExcludedFiles
QStringList _serverBlacklistedFiles; // The blacklist from the capabilities
+ QStringList _leadingAndTrailingSpacesFilesAllowed;
bool _ignoreHiddenFiles = false;
std::function<bool(const QString &)> _shouldDiscoverLocaly;
diff --git a/src/libsync/syncengine.cpp b/src/libsync/syncengine.cpp
index 0306e0f8c..ac19cd40c 100644
--- a/src/libsync/syncengine.cpp
+++ b/src/libsync/syncengine.cpp
@@ -548,6 +548,7 @@ void SyncEngine::startSync()
emit transmissionProgress(*_progressInfo);
_discoveryPhase.reset(new DiscoveryPhase);
+ _discoveryPhase->_leadingAndTrailingSpacesFilesAllowed = _leadingAndTrailingSpacesFilesAllowed;
_discoveryPhase->_account = _account;
_discoveryPhase->_excludes = _excludedFiles.data();
const QString excludeFilePath = _localPath + QStringLiteral(".sync-exclude.lst");
@@ -852,6 +853,7 @@ void SyncEngine::finalize(bool success)
_localDiscoveryStyle = LocalDiscoveryStyle::FilesystemOnly;
_clearTouchedFilesTimer.start();
+ _leadingAndTrailingSpacesFilesAllowed.clear();
}
void SyncEngine::slotProgress(const SyncFileItem &item, qint64 current)
@@ -924,6 +926,11 @@ void SyncEngine::slotClearTouchedFiles()
_touchedFiles.clear();
}
+void SyncEngine::addAcceptedInvalidFileName(const QString& filePath)
+{
+ _leadingAndTrailingSpacesFilesAllowed.append(filePath);
+}
+
bool SyncEngine::wasFileTouched(const QString &fn) const
{
// Start from the end (most recent) and look for our path. Check the time just in case.
diff --git a/src/libsync/syncengine.h b/src/libsync/syncengine.h
index 87b0cf4df..cbdb65345 100644
--- a/src/libsync/syncengine.h
+++ b/src/libsync/syncengine.h
@@ -74,6 +74,8 @@ public:
bool ignoreHiddenFiles() const { return _ignore_hidden_files; }
void setIgnoreHiddenFiles(bool ignore) { _ignore_hidden_files = ignore; }
+ void addAcceptedInvalidFileName(const QString& filePath);
+
ExcludedFiles &excludedFiles() { return *_excludedFiles; }
Utility::StopWatch &stopWatch() { return _stopWatch; }
SyncFileStatusTracker &syncFileStatusTracker() { return *_syncFileStatusTracker; }
@@ -295,6 +297,8 @@ private:
LocalDiscoveryStyle _lastLocalDiscoveryStyle = LocalDiscoveryStyle::FilesystemOnly;
LocalDiscoveryStyle _localDiscoveryStyle = LocalDiscoveryStyle::FilesystemOnly;
std::set<QString> _localDiscoveryPaths;
+
+ QStringList _leadingAndTrailingSpacesFilesAllowed;
};
}
diff --git a/src/libsync/syncresult.cpp b/src/libsync/syncresult.cpp
index 2e2c01033..c058210a4 100644
--- a/src/libsync/syncresult.cpp
+++ b/src/libsync/syncresult.cpp
@@ -141,7 +141,7 @@ void SyncResult::processCompletedItem(const SyncFileItemPtr &item)
if (!_firstItemError) {
_firstItemError = item;
}
- } else if (item->_status == SyncFileItem::Conflict) {
+ } else if (item->_status == SyncFileItem::Conflict || item->_status == SyncFileItem::FileNameInvalid) {
if (item->_instruction == CSYNC_INSTRUCTION_CONFLICT) {
_numNewConflictItems++;
if (!_firstNewConflictItem) {
diff --git a/test/testlocaldiscovery.cpp b/test/testlocaldiscovery.cpp
index 29c80e9a4..5cffb73eb 100644
--- a/test/testlocaldiscovery.cpp
+++ b/test/testlocaldiscovery.cpp
@@ -210,10 +210,10 @@ private slots:
FakeFolder fakeFolder{FileInfo{}};
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
const QString fileWithSpaces1(" foo");
- const QString fileWithSpaces2(" bar ");
+ const QString fileWithSpaces2(" bar ");
const QString fileWithSpaces3("bla ");
const QString fileWithSpaces4("A/ foo");
- const QString fileWithSpaces5("A/ bar ");
+ const QString fileWithSpaces5("A/ bar ");
const QString fileWithSpaces6("A/bla ");
fakeFolder.localModifier().insert(fileWithSpaces1);
@@ -223,76 +223,50 @@ private slots:
fakeFolder.localModifier().insert(fileWithSpaces4);
fakeFolder.localModifier().insert(fileWithSpaces5);
fakeFolder.localModifier().insert(fileWithSpaces6);
- fakeFolder.localModifier().mkdir(QStringLiteral(" with spaces "));
+ fakeFolder.localModifier().mkdir(QStringLiteral(" with spaces "));
- 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));
+ ItemCompletedSpy completeSpy(fakeFolder);
+ completeSpy.clear();
- QVERIFY(fakeFolder.currentLocalState().find("A/foo"));
- QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4));
+ QVERIFY(fakeFolder.syncOnce());
- QVERIFY(fakeFolder.currentLocalState().find("A/bar"));
- QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5));
+ QCOMPARE(completeSpy.findItem(fileWithSpaces1)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces2)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces3)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(QStringLiteral(" with spaces "))->_status, SyncFileItem::Status::FileNameInvalid);
- QVERIFY(fakeFolder.currentLocalState().find("A/bla"));
- QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6));
+ fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces1);
+ fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces2);
+ fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces3);
+ fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces4);
+ fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces5);
+ fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces6);
+ fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + QStringLiteral(" with spaces "));
- QVERIFY(fakeFolder.currentLocalState().find(QStringLiteral("with spaces")));
- QVERIFY(!fakeFolder.currentLocalState().find(QStringLiteral(" with spaces ")));
+ completeSpy.clear();
fakeFolder.syncEngine().setLocalDiscoveryOptions(LocalDiscoveryStyle::DatabaseAndFilesystem, {QStringLiteral("foo"), QStringLiteral("bar"), QStringLiteral("bla"), QStringLiteral("A/foo"), QStringLiteral("A/bar"), QStringLiteral("A/bla")});
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));
-
- QVERIFY(fakeFolder.currentRemoteState().find(QStringLiteral("with spaces")));
- QVERIFY(!fakeFolder.currentRemoteState().find(QStringLiteral(" with spaces ")));
- QVERIFY(fakeFolder.currentLocalState().find(QStringLiteral("with spaces")));
- QVERIFY(!fakeFolder.currentLocalState().find(QStringLiteral(" with spaces ")));
+ QCOMPARE(completeSpy.findItem(fileWithSpaces1)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces2)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces3)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(QStringLiteral(" with spaces "))->_status, SyncFileItem::Status::Success);
}
- void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedDoNotExist_renameFile()
+ void testCreateFileWithTrailingSpaces_remoteDontGetRenamedAutomatically()
{
- FakeFolder fakeFolder{FileInfo{}};
+ // On Windows we can't create files/folders with leading/trailing spaces locally. So, we have to fail those items. On other OSs - we just sync them down normally.
+ FakeFolder fakeFolder{FileInfo()};
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
const QString fileWithSpaces4("A/ foo");
- const QString fileWithSpaces5("A/ bar ");
+ const QString fileWithSpaces5("A/ bar ");
const QString fileWithSpaces6("A/bla ");
fakeFolder.remoteModifier().mkdir("A");
@@ -300,43 +274,69 @@ private slots:
fakeFolder.remoteModifier().insert(fileWithSpaces5);
fakeFolder.remoteModifier().insert(fileWithSpaces6);
- qDebug() << fakeFolder.currentRemoteState();
+ ItemCompletedSpy completeSpy(fakeFolder);
+ completeSpy.clear();
QVERIFY(fakeFolder.syncOnce());
- qDebug() << fakeFolder.currentRemoteState();
+ if (Utility::isWindows()) {
+ QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::FileNameInvalid);
+ } else {
+ QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::Success);
+ }
+ }
- QVERIFY(fakeFolder.currentRemoteState().find("A/foo"));
- QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4));
+ void testCreateFileWithTrailingSpaces_remoteGetRenamedManually()
+ {
+ // On Windows we can't create files/folders with leading/trailing spaces locally. So, we have to fail those items. On other OSs - we just sync them down normally.
+ FakeFolder fakeFolder{FileInfo()};
+ QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
+ const QString fileWithSpaces4("A/ foo");
+ const QString fileWithSpaces5("A/ bar ");
+ const QString fileWithSpaces6("A/bla ");
+
+ const QString fileWithoutSpaces4("A/foo");
+ const QString fileWithoutSpaces5("A/bar");
+ const QString fileWithoutSpaces6("A/bla");
+
+ fakeFolder.remoteModifier().mkdir("A");
+ fakeFolder.remoteModifier().insert(fileWithSpaces4);
+ fakeFolder.remoteModifier().insert(fileWithSpaces5);
+ fakeFolder.remoteModifier().insert(fileWithSpaces6);
- QVERIFY(fakeFolder.currentRemoteState().find("A/bar"));
- QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5));
+ ItemCompletedSpy completeSpy(fakeFolder);
+ completeSpy.clear();
- QVERIFY(fakeFolder.currentRemoteState().find("A/bla"));
- QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6));
+ QVERIFY(fakeFolder.syncOnce());
- QVERIFY(fakeFolder.syncOnce());
+ if (Utility::isWindows()) {
+ QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::FileNameInvalid);
+ } else {
+ QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::Success);
+ }
- QVERIFY(fakeFolder.currentRemoteState().find("A/foo"));
- QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4));
- QVERIFY(fakeFolder.currentLocalState().find("A/foo"));
- QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4));
+ fakeFolder.remoteModifier().rename(fileWithSpaces4, fileWithoutSpaces4);
+ fakeFolder.remoteModifier().rename(fileWithSpaces5, fileWithoutSpaces5);
+ fakeFolder.remoteModifier().rename(fileWithSpaces6, fileWithoutSpaces6);
- QVERIFY(fakeFolder.currentRemoteState().find("A/bar"));
- QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5));
- QVERIFY(fakeFolder.currentLocalState().find("A/bar"));
- QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5));
+ completeSpy.clear();
- QVERIFY(fakeFolder.currentRemoteState().find("A/bla"));
- QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6));
- QVERIFY(fakeFolder.currentLocalState().find("A/bla"));
- QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6));
+ QVERIFY(fakeFolder.syncOnce());
- auto expectedState = fakeFolder.currentLocalState();
- QCOMPARE(fakeFolder.currentRemoteState(), expectedState);
+ QCOMPARE(completeSpy.findItem(fileWithoutSpaces4)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithoutSpaces5)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithoutSpaces6)->_status, SyncFileItem::Status::Success);
}
- void testCreateFileWithTrailingSpaces_localTrimmedDoesExist_dontRenameAndUploadFile()
+ void testCreateFileWithTrailingSpaces_localTrimmedAlsoCreated_dontRenameAutomaticallyAndDontUploadFile()
{
FakeFolder fakeFolder{FileInfo{}};
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
@@ -344,9 +344,9 @@ private slots:
const QString fileTrimmed("foo");
fakeFolder.localModifier().insert(fileTrimmed);
- QVERIFY(fakeFolder.syncOnce());
fakeFolder.localModifier().insert(fileWithSpaces);
- QVERIFY(!fakeFolder.syncOnce());
+
+ QVERIFY(fakeFolder.syncOnce());
QVERIFY(fakeFolder.currentRemoteState().find(fileTrimmed));
QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces));
@@ -354,7 +354,7 @@ private slots:
QVERIFY(fakeFolder.currentLocalState().find(fileTrimmed));
}
- void testCreateFileWithTrailingSpaces_localTrimmedAlsoCreated_dontRenameAndUploadFile()
+ void testCreateFileWithTrailingSpaces_localTrimmedAlsoCreated_dontRenameAutomaticallyAndUploadBothFiles()
{
FakeFolder fakeFolder{FileInfo{}};
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
@@ -363,10 +363,13 @@ private slots:
fakeFolder.localModifier().insert(fileTrimmed);
fakeFolder.localModifier().insert(fileWithSpaces);
- QVERIFY(!fakeFolder.syncOnce());
+
+ fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces);
+
+ QVERIFY(fakeFolder.syncOnce());
QVERIFY(fakeFolder.currentRemoteState().find(fileTrimmed));
- QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces));
+ QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces));
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces));
QVERIFY(fakeFolder.currentLocalState().find(fileTrimmed));
}
@@ -376,7 +379,7 @@ private slots:
FakeFolder fakeFolder{FileInfo{}};
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
const QString fileWithSpaces1(" foo");
- const QString fileWithSpaces2(" bar ");
+ const QString fileWithSpaces2(" bar ");
const QString fileWithSpaces3("bla ");
fakeFolder.localModifier().insert(fileWithSpaces1);
diff --git a/test/testsyncvirtualfiles.cpp b/test/testsyncvirtualfiles.cpp
index bff6488e4..425305b65 100644
--- a/test/testsyncvirtualfiles.cpp
+++ b/test/testsyncvirtualfiles.cpp
@@ -763,17 +763,17 @@ private slots:
QVERIFY(dbRecord(fakeFolder, "case6-rename")._type == ItemTypeFile);
}
- void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedDoNotExist_renameAndUploadFile()
+ void testCreateFileWithTrailingSpaces_acceptAndRejectInvalidFileName()
{
FakeFolder fakeFolder{ FileInfo() };
setupVfs(fakeFolder);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
const QString fileWithSpaces1(" foo");
- const QString fileWithSpaces2(" bar ");
+ const QString fileWithSpaces2(" bar ");
const QString fileWithSpaces3("bla ");
const QString fileWithSpaces4("A/ foo");
- const QString fileWithSpaces5("A/ bar ");
+ const QString fileWithSpaces5("A/ bar ");
const QString fileWithSpaces6("A/bla ");
fakeFolder.localModifier().insert(fileWithSpaces1);
@@ -783,101 +783,133 @@ private slots:
fakeFolder.localModifier().insert(fileWithSpaces4);
fakeFolder.localModifier().insert(fileWithSpaces5);
fakeFolder.localModifier().insert(fileWithSpaces6);
+
+ ItemCompletedSpy completeSpy(fakeFolder);
+ completeSpy.clear();
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));
+ QCOMPARE(completeSpy.findItem(fileWithSpaces1)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces2)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces3)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::FileNameInvalid);
- QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces3.trimmed()));
- QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces3));
+ fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces1);
+ fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces2);
+ fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces3);
+ fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces4);
+ fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces5);
+ fakeFolder.syncEngine().addAcceptedInvalidFileName(fakeFolder.localPath() + fileWithSpaces6);
- QVERIFY(fakeFolder.currentLocalState().find("A/foo"));
- QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4));
+ completeSpy.clear();
- QVERIFY(fakeFolder.currentLocalState().find("A/bar"));
- QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5));
+ QVERIFY(fakeFolder.syncOnce());
- QVERIFY(fakeFolder.currentLocalState().find("A/bla"));
- QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces6));
+ QCOMPARE(completeSpy.findItem(fileWithSpaces1)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces2)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces3)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::Success);
+ }
- QVERIFY(fakeFolder.syncOnce());
+ void testCreateFileWithTrailingSpaces_remoteDontGetRenamedAutomatically()
+ {
+ // On Windows we can't create files/folders with leading/trailing spaces locally. So, we have to fail those items. On other OSs - we just sync them down normally.
+ 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 ");
- QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces1.trimmed()));
- QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces1));
- QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces1.trimmed()));
- QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces1));
+ const QString fileWithSpacesVirtual4(fileWithSpaces4 + DVSUFFIX);
+ const QString fileWithSpacesVirtual5(fileWithSpaces5 + DVSUFFIX);
+ const QString fileWithSpacesVirtual6(fileWithSpaces6 + DVSUFFIX);
- QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces2.trimmed()));
- QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces2));
- QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces2.trimmed()));
- QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces2));
+ fakeFolder.remoteModifier().mkdir("A");
+ fakeFolder.remoteModifier().insert(fileWithSpaces4);
+ fakeFolder.remoteModifier().insert(fileWithSpaces5);
+ fakeFolder.remoteModifier().insert(fileWithSpaces6);
- QVERIFY(fakeFolder.currentRemoteState().find(fileWithSpaces3.trimmed()));
- QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces3));
- QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces3.trimmed()));
- QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces3));
+ ItemCompletedSpy completeSpy(fakeFolder);
+ completeSpy.clear();
- QVERIFY(fakeFolder.currentRemoteState().find("A/foo"));
- QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4));
- QVERIFY(fakeFolder.currentLocalState().find("A/foo"));
- QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces4));
+ QVERIFY(fakeFolder.syncOnce());
- QVERIFY(fakeFolder.currentRemoteState().find("A/bar"));
- QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5));
- QVERIFY(fakeFolder.currentLocalState().find("A/bar"));
- QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces5));
+ if (Utility::isWindows()) {
+ QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::FileNameInvalid);
+ } else {
+ QCOMPARE(completeSpy.findItem(fileWithSpacesVirtual4)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpacesVirtual5)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpacesVirtual6)->_status, SyncFileItem::Status::Success);
+ }
- 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()
+ void testCreateFileWithTrailingSpaces_remoteGetRenamedManually()
{
- FakeFolder fakeFolder{ FileInfo() };
+ // On Windows we can't create files/folders with leading/trailing spaces locally. So, we have to fail those items. On other OSs - we just sync them down normally.
+ FakeFolder fakeFolder{FileInfo()};
setupVfs(fakeFolder);
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
const QString fileWithSpaces4("A/ foo");
- const QString fileWithSpaces5("A/ bar ");
+ const QString fileWithSpaces5("A/ bar ");
const QString fileWithSpaces6("A/bla ");
+ const QString fileWithSpacesVirtual4(fileWithSpaces4 + DVSUFFIX);
+ const QString fileWithSpacesVirtual5(fileWithSpaces5 + DVSUFFIX);
+ const QString fileWithSpacesVirtual6(fileWithSpaces6 + DVSUFFIX);
+
+ const QString fileWithoutSpaces4("A/foo");
+ const QString fileWithoutSpaces5("A/bar");
+ const QString fileWithoutSpaces6("A/bla");
+
+ const QString fileWithoutSpacesVirtual4(fileWithoutSpaces4 + DVSUFFIX);
+ const QString fileWithoutSpacesVirtual5(fileWithoutSpaces5 + DVSUFFIX);
+ const QString fileWithoutSpacesVirtual6(fileWithoutSpaces6 + DVSUFFIX);
+
fakeFolder.remoteModifier().mkdir("A");
fakeFolder.remoteModifier().insert(fileWithSpaces4);
fakeFolder.remoteModifier().insert(fileWithSpaces5);
fakeFolder.remoteModifier().insert(fileWithSpaces6);
- QVERIFY(fakeFolder.syncOnce());
+ ItemCompletedSpy completeSpy(fakeFolder);
+ completeSpy.clear();
- QVERIFY(fakeFolder.currentRemoteState().find("A/foo"));
- QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces4));
+ QVERIFY(fakeFolder.syncOnce());
- QVERIFY(fakeFolder.currentRemoteState().find("A/bar"));
- QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces5));
+ if (Utility::isWindows()) {
+ QCOMPARE(completeSpy.findItem(fileWithSpaces4)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces5)->_status, SyncFileItem::Status::FileNameInvalid);
+ QCOMPARE(completeSpy.findItem(fileWithSpaces6)->_status, SyncFileItem::Status::FileNameInvalid);
+ } else {
+ QCOMPARE(completeSpy.findItem(fileWithSpacesVirtual4)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpacesVirtual5)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithSpacesVirtual6)->_status, SyncFileItem::Status::Success);
+ }
+
+ fakeFolder.remoteModifier().rename(fileWithSpaces4, fileWithoutSpaces4);
+ fakeFolder.remoteModifier().rename(fileWithSpaces5, fileWithoutSpaces5);
+ fakeFolder.remoteModifier().rename(fileWithSpaces6, fileWithoutSpaces6);
- QVERIFY(fakeFolder.currentRemoteState().find("A/bla"));
- QVERIFY(!fakeFolder.currentRemoteState().find(fileWithSpaces6));
+ completeSpy.clear();
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}));
+ if (Utility::isWindows()) {
+ QCOMPARE(completeSpy.findItem(fileWithoutSpaces4 + DVSUFFIX)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithoutSpaces5 + DVSUFFIX)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithoutSpaces6 + DVSUFFIX)->_status, SyncFileItem::Status::Success);
+ } else {
+ QCOMPARE(completeSpy.findItem(fileWithoutSpacesVirtual4)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithoutSpacesVirtual5)->_status, SyncFileItem::Status::Success);
+ QCOMPARE(completeSpy.findItem(fileWithoutSpacesVirtual6)->_status, SyncFileItem::Status::Success);
+ }
}
// Dehydration via sync works