mirror of
https://github.com/nextcloud/desktop.git
synced 2025-10-26 11:17:43 +00:00
Merge pull request #4454 from nextcloud/bugfix/allow-manual-rename-files-with-spaces
Bugfix/allow manual rename files with spaces
This commit is contained in:
commit
fc8bfdc9f3
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -1225,6 +1225,11 @@ void Folder::scheduleThisFolderSoon()
|
||||
}
|
||||
}
|
||||
|
||||
void Folder::acceptInvalidFileName(const QString &filePath)
|
||||
{
|
||||
_engine->addAcceptedInvalidFileName(filePath);
|
||||
}
|
||||
|
||||
void Folder::setSaveBackwardsCompatible(bool save)
|
||||
{
|
||||
_saveBackwardsCompatible = save;
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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::onCheckIfAllowedToRenameComplete(const QVariantMap &values, QNetworkReply *reply)
|
||||
{
|
||||
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."));
|
||||
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)
|
||||
{
|
||||
if (!values.contains("permissions")) {
|
||||
return;
|
||||
}
|
||||
const auto remotePermissions = RemotePermissions::fromServerString(values["permissions"].toString());
|
||||
if (!remotePermissions.hasPermission(remotePermissions.CanRename)
|
||||
|| !remotePermissions.hasPermission(remotePermissions.CanMove)) {
|
||||
_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);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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.
|
||||
*
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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 "));
|
||||
|
||||
ItemCompletedSpy completeSpy(fakeFolder);
|
||||
completeSpy.clear();
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
QVERIFY(fakeFolder.currentLocalState().find(fileWithSpaces1.trimmed()));
|
||||
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces1));
|
||||
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(fileWithSpaces2.trimmed()));
|
||||
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces2));
|
||||
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(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.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();
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void testCreateFileWithTrailingSpaces_localTrimmedDoesExist_dontRenameAndUploadFile()
|
||||
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);
|
||||
|
||||
ItemCompletedSpy completeSpy(fakeFolder);
|
||||
completeSpy.clear();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
fakeFolder.remoteModifier().rename(fileWithSpaces4, fileWithoutSpaces4);
|
||||
fakeFolder.remoteModifier().rename(fileWithSpaces5, fileWithoutSpaces5);
|
||||
fakeFolder.remoteModifier().rename(fileWithSpaces6, fileWithoutSpaces6);
|
||||
|
||||
completeSpy.clear();
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
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_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);
|
||||
|
||||
@ -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));
|
||||
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(fileWithSpaces2.trimmed()));
|
||||
QVERIFY(!fakeFolder.currentLocalState().find(fileWithSpaces2));
|
||||
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(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));
|
||||
completeSpy.clear();
|
||||
|
||||
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));
|
||||
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);
|
||||
}
|
||||
|
||||
void testCreateFileWithTrailingSpaces_localAndRemoteTrimmedDoNotExist_renameFile()
|
||||
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 fileWithSpaces5("A/ bar ");
|
||||
const QString fileWithSpaces6("A/bla ");
|
||||
|
||||
const QString fileWithSpacesVirtual4(fileWithSpaces4 + DVSUFFIX);
|
||||
const QString fileWithSpacesVirtual5(fileWithSpaces5 + DVSUFFIX);
|
||||
const QString fileWithSpacesVirtual6(fileWithSpaces6 + DVSUFFIX);
|
||||
|
||||
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));
|
||||
ItemCompletedSpy completeSpy(fakeFolder);
|
||||
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}));
|
||||
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/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}));
|
||||
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()};
|
||||
setupVfs(fakeFolder);
|
||||
QCOMPARE(fakeFolder.currentLocalState(), fakeFolder.currentRemoteState());
|
||||
const QString fileWithSpaces4("A/ foo");
|
||||
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);
|
||||
|
||||
ItemCompletedSpy completeSpy(fakeFolder);
|
||||
completeSpy.clear();
|
||||
|
||||
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(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);
|
||||
|
||||
completeSpy.clear();
|
||||
|
||||
QVERIFY(fakeFolder.syncOnce());
|
||||
|
||||
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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user